• 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
    ",dp[1][0]);
        }
        return 0;
    }
  • 相关阅读:
    gsm at 指令
    wm8976 codec
    【Gym 100971J】Robots at Warehouse
    【XDU1144】合并模板
    腾讯云CentOS7安装LNMP+wordpress
    【USACO1.1】Broken Necklace
    【校赛小分队之我们有个女生】训练赛6
    【计导作业】——商品记录
    C 文件读写2
    C 文件读写1
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3254920.html
Copyright © 2020-2023  润新知