zoukankan      html  css  js  c++  java
  • 蒟蒻的树形dp记录

    POJ2342:

    题意:某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知每个人的活跃指数和上司关系(当然不可能存在环),求邀请哪些人(多少人)来能使得晚会的总活跃指数最大。

    题解:

    当i来的时候,dp[i][1] += dp[j][0];//j为i的下属

    当i不来的时候,dp[i][0] +=max(dp[j][1],dp[j][0]);//j为i的下属

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <queue>
    #include <typeinfo>
    #include <map>
    //#include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    #define inf 10000000
    inline ll read()
    {
        ll x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    //***************************************************************
    
    int dp[10000][2];
    int vis[10000];
    int parent[10000];
    int n,a,b;
    void sp(int x)
    {
        vis[x]=1;
        for(int i=1;i<=n;i++)
        {
            if(parent[i]==x&&!vis[i])
            {
                sp(i);
                dp[x][0]+=max(dp[i][0],dp[i][1]);
                dp[x][1]+=dp[i][0];
            }
        }
    }
    int main()
    {
    
        while(cin>>n)
        {  memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++)
                scanf("%d",&dp[i][1]);
                memset(vis,0,sizeof(vis));
    
                int root=0;
                memset(parent,0,sizeof(parent));
            while(scanf("%d%d",&a,&b)&&a&&b)
            {
                parent[a]=b;
                root=b;
            }
            sp(root);
            printf("%d
    ",max(dp[root][0],dp[root][1]));
        }
        return 0;
    }
    代码狗

     vijos1642

    题解:我们先依次求出每棵树的先根遍历序,并保存在同一个序列list[]中。 为了利用上面的结论,我们还要求出以节点i为根的子树的节点总数count[i]。 

    定义: v[i]表示第i个物品的权值 dp[i][j]表示从第i个物品到第n个物品,最多花费j,能得到的最大权值和。

    状态转移: 对于一个节点,我们考虑是否购买它: 购买:那么我们继续考虑它后面的节点 不购买:那么我们跳过它的子孙节点

    方程如下: F[i][j]=Max{F[i+1][j-cost[list[i]]]+weight[list[i]],F[i+count[list[i]]][j]} 

    ///1085422276
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <queue>
    #include <typeinfo>
    #include <map>
    typedef long long ll;
    using namespace std;
    #define inf 10000000
    inline ll read()
    {
        ll x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    //***************************************************************
    ///先根遍历序
    int list[10005];
    int s[1005],a[1081][1008];
    int v[10001],counts[1901];
    int dp[1091][1991];
    int q;
    int n,m;
    int dfs(int k)
    {
        list[++q]=k; 
        if(s[k]==0){return ++counts[k];}
        for(int i=1;i<=s[k];i++)
        {
            counts[k]+=dfs(a[k][i]);
        }
        return ++counts[k];
    }
    int main()
    {
     int  t;
         memset(dp,-127,sizeof(dp));
         scanf("%d%d",&n,&m);
         for(int i=1;i<=n;i++)
         {
    
             scanf("%d%d",&v[i],&t);
         while(t--)
             {
                 scanf("%d",&a[i][++s[i]]);
             }
         }
         dfs(1);
         for(int i=1;i<=n;i++){dp[i][0]=0;dp[i][1]=v[list[i]];}
           for(int i=n-1;i>=0;i--)
           {
               for(int j=1;j<=m;j++)
               {
                   dp[i][j]=max(dp[i+1][j-1]+v[list[i]],dp[i+counts[list[i]]][j]);
               }
           }
           int ans=-inf;
           for(int i=1;i<=m;i++)
            ans=max(dp[1][i],ans);
            printf("%d
    ",max(ans,0));
        return 0;
    }
    代码狗

     POJ 1947

    题解:dp[root][i]表示以root为根得到节点数为i 所需要删除的少边数

    转移:

    dp[root][i]=dp[root][i]+1;  不加某son,边+1;

    dp[root][i]=min(dp[root][i-j]+dp[son][j]);加某son,j代表son为根的树节点数

    最后注意:非根节点边数+1;因为要删除与父亲节点的边

    ///1085422276
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <queue>
    #include <typeinfo>
    #include <map>
    typedef long long ll;
    using namespace std;
    #define inf 10000000
    inline ll read()
    {
        ll x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    //***************************************************************
    int dp[200][200];
    vector<int  >son[200];
    int dfs(int root,int pre)
    {
        dp[root][1]=0;
        int sum=1;
        for(int i=0;i<son[root].size();i++)
        {
            int s=son[root][i];
            if(s==pre)continue;
            sum+=dfs(s,root);
            for(int  k=sum;k>=1;k--)
            {
                dp[root][k]=dp[root][k]+1;
                for(int h=1;h<k;h++)
                {
                    dp[root][k]=min(dp[root][k],dp[root][k-h]+dp[s][h]);
                }
            }
        }
        return sum;
    }
    int main()
    {
        int n,m,a,b;
        memset(dp,127,sizeof(dp));
        scanf("%d%d",&n,&m);
       // for(int i=1;i<=n;i++)dp[i][0]=1;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            son[a].push_back(b);
            son[b].push_back(a);
        }
        dfs(1,-1);
        int ans=dp[1][m];
        for(int i=2;i<=n;i++){
            if(dp[i][m]+1<ans)ans=dp[i][m]+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    代码

     HDU 1011 Starship Troopers

    转移:dp[i][k] = max(dp[i][k], dp[i][k-l] + dp[i][l]);

    //зїеп:1085422276
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <queue>
    #include <typeinfo>
    #include <map>
    #include <stack>
    typedef long long ll;
    #define inf 100000000
    using namespace std;
    
    inline ll read()
    {
        ll x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    //***************************************
    int v[888];
    int cost[888];
    int dp[333][333];
    vector<int >tr[333];
    int n,m;
    void dfs(int k,int pre)
    {
        for(int i=cost[k];i<=m;i++)
            dp[k][i]=v[k];
        for(int i=0;i<tr[k].size();i++){
            if(pre==tr[k][i])continue;
            dfs(tr[k][i],k);
            int son=tr[k][i];
            for(int j=m;j>=cost[k];j--)
            {
                for(int l=1;l+cost[k]<=j;l++)
                {
                    dp[k][j]=max(dp[k][j],dp[son][l]+dp[k][j-l]);
                }
            }
        }
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            if(n==-1&&m==-1)break;
           // init();
           memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d",&cost[i],&v[i]);
                cost[i]=cost[i]/20+(cost[i]%20!=0);
               // if(cost[i]%20!=0)cost[i]+=1;
                tr[i].clear();
            }
            int a,b;
            for(int i=1;i<n;i++)
            {
                scanf("%d%d",&a,&b);
                tr[a].push_back(b);
                tr[b].push_back(a);
            } 
            if(m==0){printf("0
    ");continue;}
            dfs(1,-1);
            printf("%d
    ",dp[1][m]);
        }
        return 0;
    }
    代码

    CodeForces 161D Distance in Tree

    题目链接:http://codeforces.com/contest/161/problem/D

    简单树形dp:维护各个节点1到k的情况就可以了;

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <queue>
    #include <typeinfo>
    #include <map>
    #include <stack>
    typedef long long ll;
    using namespace std;
    inline ll read()
    {
        ll x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    //**************************************************************************************
    ll ans,dp[50005][505];///以i为节点构成路径长度为j的种类树;
    vector<int >G[50005];
    int fa[50005];
    int vis[50005];
    int n,m;
    void  dfs(int k)
    {
        dp[k][0]=1;
      for(int i=0;i<G[k].size();i++){
        int son=G[k][i];
        if(vis[son])continue;
        vis[son]=1;
        dfs(son);
        for(int j=0;j<m;j++){
            ans+=dp[k][m-j-1]*dp[son][j];
        }
        for(int i=1;i<=m;i++)
        {
            dp[k][i]+=dp[son][i-1];
        }
      }
    }
    
    
    int main()
    {
    
        scanf("%d%d",&n,&m);
        int a,b;
        for(int i=1;i<n;i++){
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
        }
        memset(vis,0,sizeof(vis));
        memset(dp,0,sizeof(dp));
        vis[1]=1;
        dfs(1);
    
    
       cout<<ans<<endl;
        return 0;
    }
    代码

     【tyvj1520】树的直径

    题目链接:http://www.tyvj.cn/p/1520

    dp1[],dp2[]分别代表从当前根节点出发所能到达的最长链与次长链,感谢HZWER指点;。。。。。

    ///1085422276
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <queue>
    #include <typeinfo>
    #include <map>
    typedef long long ll;
    using namespace std;
    #define inf 10000000
    inline ll read()
    {
        ll x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-')f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
    //***************************************************************
    
    struct ss
    {
        int to,next,v;
    }e[10001*2];
    int head[10001],t,dp1[10001],dp2[10001],ans;
    void add(int u,int v,int w)
    {
        e[t].to=v;
        e[t].next=head[u];
        e[t].v=w;
        head[u]=t++;
    }
    void dp(int x,int pre)
    {
        for(int i=head[x];i;i=e[i].next)
        {
            if(e[i].to==pre)continue;
            dp(e[i].to,x);
            if(dp1[e[i].to]+e[i].v>dp1[x])
            {
                dp2[x]=dp1[x];
                dp1[x]=dp1[e[i].to]+e[i].v;
            }
            else dp2[x]=max(dp1[e[i].to]+e[i].v,dp2[x]);
        }
        ans=max(dp1[x]+dp2[x],ans);
    }
    int main()
    {int n;
    memset(head,0,sizeof(head));
    t=1;
    ans=0;
    int u,v,w;
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,w);
        }
        dp(1,0);
        cout<<ans<<endl;
    
        return 0;
    }
    代码
  • 相关阅读:
    Git操作命令2-在Git仓库里管理文件历史-分支操作
    mvvmlight框架搭建VS版本不同导致的问题
    wpf命令详解
    wpf触发器
    wpf控件模型
    wpf中Interaction.Behaviors详解
    wpf附加属性详解
    wpf依赖属性概述
    wpf体系结构
    MySql5.7下载安装配置教程
  • 原文地址:https://www.cnblogs.com/zxhl/p/4744769.html
Copyright © 2011-2022 走看看