【UVALive4685-Succession】树形DP

http://acm.hust.edu.cn/vjudge/problem/14338

题意:给定一棵树,每个点有一个值,让你选择k个点,并且这k个点是连在一起的(从任意一个点出发,可以遍历完所有选择的点 并且 不经过没有被选择的点),让这k个点的价值总和最大,纹方案数(Mod1000000007)。

题解:设d[x][k]为必须选择x,以x为根的子树中共选择了k个节点,价值总和最大是多少。

       f[x][k]为d[x][k]对应的方案数是多少。

对于x,我们把x的孩子son不断地并到f[x]中。

对于每一个son:d[x][j]=maxx(d[x][j-k],d[son][k]);

需要注意的就是上式中d[x][j]不断地变化,对于当前的son,j变大的时候可能用到的d[x][j-k]是用当前的son更新的。所以要开一个p[x][j]等于当前的son没更新x的时候d[x][j]的值,同理q[x][j]=f[x][j]。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 typedef long long LL;
  9 const int N=110;
 10 const LL Inf=(LL)1e9,Mod=1000000007;
 11 struct node{
 12     int x,y,next;
 13 }a[2*N];
 14 int len,n,m,r;
 15 int first[N],son[N],w[N];
 16 LL a1,a2,d[N][N],f[N][N],p[N][N],q[N][N];
 17 
 18 void ins(int x,int y)
 19 {
 20     len++;
 21     a[len].x=x;a[len].y=y;
 22     a[len].next=first[x];first[x]=len;
 23 }
 24 
 25 void dfs(int x,int fa)
 26 {
 27     son[x]=1;
 28     for(int i=first[x];i;i=a[i].next)
 29     {
 30         int y=a[i].y;
 31         if(y==fa) continue;
 32         dfs(y,x);
 33         son[x]+=son[y];
 34     }
 35 }
 36 
 37 void copy(int x)
 38 {
 39     for(int i=0;i<=n;i++) p[x][i]=d[x][i],q[x][i]=f[x][i];
 40 }
 41 
 42 void dp(int x,int fa)
 43 {
 44     for(int i=1;i<=n;i++) d[x][i]=-Inf;
 45     memset(f[x],0,sizeof(f[x]));
 46     d[x][0]=0;f[x][0]=1;d[x][1]=w[x];f[x][1]=1;
 47     
 48     copy(x);
 49     
 50     for(int i=first[x];i;i=a[i].next)
 51     {
 52         int y=a[i].y;
 53         if(y==fa) continue;
 54         dp(y,x);
 55         for(int j=2;j<=son[x];j++)
 56         {
 57             for(int k=1;k<=son[y] && (j-k)>=1;k++)
 58             {
 59                 LL dd=p[x][j-k]+d[y][k];
 60                 LL ff=(q[x][j-k]*f[y][k])%Mod;
 61                 if(dd > p[x][j]) 
 62                 {
 63                     if(dd>d[x][j]) d[x][j]=dd,f[x][j]=ff;
 64                     else if(dd==d[x][j]) f[x][j]=(f[x][j]+ff)%Mod;
 65                 }
 66                 else if(dd == p[x][j])
 67                 {
 68                     if(dd==d[x][j]) f[x][j]=(f[x][j]+ff)%Mod;
 69                 }
 70             }
 71         }
 72         copy(x);
 73     }
 74     
 75     if(d[x][m]>a1) a1=d[x][m],a2=f[x][m];
 76     else if(d[x][m]==a1) a2=(a2+f[x][m])%Mod;
 77 }
 78 
 79 int main()
 80 {
 81     freopen("a.in","r",stdin);
 82     // freopen("a.out","w",stdout);    
 83     int T;
 84     scanf("%d",&T);
 85     while(T--)
 86     {
 87         len=0;
 88         memset(first,0,sizeof(first));
 89         scanf("%d%d%d",&n,&m,&r);
 90         for(int i=1;i<=n;i++) scanf("%d",&w[i]);
 91         for(int i=1;i<=r;i++)
 92         {
 93             int x,y;
 94             scanf("%d%d",&x,&y);
 95             x++;y++;
 96             ins(x,y);ins(y,x);
 97         }
 98         dfs(1,0);
 99         a1=-Inf;
100         dp(1,0);
101         printf("%I64d %I64d
",a1,a2);
102     }
103     return 0;
104 }
原文地址:https://www.cnblogs.com/KonjakJuruo/p/5785400.html