hdu 4582ツリーDP

8052 ワード

構想:まず声明します.私は参考にします.http://blog.csdn.net/frog1902/article/details/9921845この大牛のブログです.
彼の話はもう詳しくなりましたが、やはりいくつか補足したいです.
彼の解題報告を見てから私のほうがいいです.
私のこのback[i]は彼のlim[i]に対してです.
私が追加したいのは、バック[i]は本当のバック[i]ではなく、この行のコードを見ることができます.バック[u]=max(back[u],dep[v]+1);つまり、それは祖ノードに戻り、さらに下のノードに戻るということです.
リターン・サイドがない点については、バックノードがルートノードにあることに相当し、ノードからルートノードのいずれかのエッジが選択されても良い.
dpの場合は、まずdp[u][i](=i<=dep[u])を0にし、uからback[u]までの間にもう一方のノードが選択されているという意味で、サブノードがあることを考慮しないと、必要な辺数は0となる.dp[u][dep[u]++の意味は、dep[u]を親ノードの端に選択する点がu自身であるということです.
私が一番理解しにくいのはdp[u][j]に対して、dp[v]と0<=k==jの深さの中から一番小さいdp[v][k]を選んで、dp[u][j]の値を求めることです.
dp[u][j]の意味は、親ノードの側に深さjのノードが選択された後、uを根とする子樹はどれぐらいの辺が必要かということであるので、この値、つまり、深さjのノードを親ノードの側に選択した後、そのサブノードを根とするdp[v][j]がすでに確定している必要がある.(前提はすべての選択は合法的でなければなりません.合法的なのはこの辺がback[u]からuの道にあるということです.)
#include<iostream>

#include<cstring>

#include<algorithm>

#include<cstdio>

#include<vector>

#define Maxn 2010

using namespace std;

int dp[Maxn][Maxn],dep[Maxn],back[Maxn],n,m,vi[Maxn];

vector<int> head[Maxn];

void init()

{

    memset(dp,-1,sizeof(dp));

    memset(dep,0,sizeof(dep));

    memset(vi,0,sizeof(vi));

    memset(back,0,sizeof(back));

    for(int i=0;i<=n;i++)

        head[i].clear();

}

void add(int u,int v)

{

    head[u].push_back(v);

    head[v].push_back(u);

}

void dfs(int u)

{

    int i,v,sz;

    vi[u]=1;

    sz=head[u].size();

    for(i=0;i<sz;i++)

    {

        v=head[u][i];

        if(vi[v]) continue;

        dep[v]=dep[u]+1;

        dfs(v);

    }

}

void Treedp(int u)

{

    int i,v,sz,j;

    vi[u]=1;

    sz=head[u].size();

    for(i=back[u];i<=dep[u];i++)

        dp[u][i]=0;

    for(i=0;i<sz;i++)

    {

        v=head[u][i];

        if(vi[v]) continue;

        Treedp(v);

        int temp=dp[v][dep[v]];

        for(j=0;j<=dep[u];j++)

        {

            if(dp[v][j]!=-1)

            {

                if(temp!=-1)

                    temp=min(temp,dp[v][j]);

                else

                    temp=dp[v][j];

            }

            if(j>=back[u])

            {

                if(temp!=-1)

                    dp[u][j]+=temp;

            }

        }

    }

    if(u!=1)

    dp[u][dep[u]]++;

}

int main()

{

    int i,j,u,v;

    while(scanf("%d%d",&n,&m)!=EOF,n||m)

    {

        init();

        for(i=1;i<n;i++)

        {

            scanf("%d%d",&u,&v);

            add(u,v);

        }

        dfs(1);

        for(i=n;i<=m;i++)

        {

            scanf("%d%d",&u,&v);

            if(dep[u]<dep[v])

                swap(u,v);

            back[u]=max(back[u],dep[v]+1);

        }

        memset(vi,0,sizeof(vi));

        Treedp(1);

        printf("%d
",dp[1][0]); } return 0; }