hdu 4582 树状DP

思路:首先声明我是参考:http://blog.csdn.net/frog1902/article/details/9921845这位大牛的博客的。

他说的已经很详尽,但我还是要补充几点。

看完他的解题报告在看我的才好些。

我这的back[i]对于他的lim[i]。

我要补充的是,back[i]不是真正的back[i],可以看到这行代码:back[u]=max(back[u],dep[v]+1);也就是说是其返回祖节点再往下的一个节点。

对于没有回退边的点,其back[i]==0相当于有一个回退边到根节点,那么本节点到根节点上的任何一条边被选择都是可行的。

dp时,首先将dp[u][i](back[u]<=i<=dep[u])置为0,意义是如果在u到back[u]之间已经有一条边被其他节点选择了,那么其不考虑有子节点的话,需要的边数就是0。dp[u][dep[u]]++的意义是选择dep[u]到其父节点的边的点正是u自己。

我个人认为最难理解的是对于dp[u][j],要从dp[v][dep[v]]与0<=k<=j的深度中选取最小的dp[v][k]求和作为dp[u][j]的值。

由于dp[u][j]的意义是选择了深度为j的节点到其父节点的边后,以u为根的子树仍需要多少边,那么可以这个值也就是选择了深度为j的节点到其父节点的边后,以其子节点为根还需要dp[v][j]已经确定,那么自然以u为根的需要边数就是其子节点需要边数的和(前提是所有的选边一定要合法,合法的就是这条边一定要在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\n",dp[1][0]);

    }

    return 0;

}

 

你可能感兴趣的:(HDU)