【UVA12093】Protecting Zonk (树形DP)
题意:
给定一个有n个节点的无根树,有两种装置A和B,每种都有无限多个。在某个节点X使用A装置需要C1的花费,并且此时与节点X相连的边都被覆盖。在某个节点X使用B装置需要C2的花费,并且此时与节点X相连的边以及与X相连的点相连的边都被覆盖。求覆盖所有边的最小花费。
分析:
首先无根树可以先dfs确定根。考虑选择装置A和装置B的影响。
装置A只会影响节点u连出去的边。而装置B还会影响u相连的点相连的边,也就是说与节点u距离为2的边也会被影响。
也就是说,对于边(u,fa[u]),如果fa[fa[u]]装上装置B,那么这条边就被覆盖。但只有这种情况吗?有一个容易漏的情况就是如果u、v的父亲都是fa[u],如果在v上装了装置B,那么边(u,fa[u])就被覆盖了。(像我这种想东西不全面的人就容易把这种情况漏掉,导致我后来整个代码重打了一遍~~)
而对于装置A,处理过程就相对简单了,下面我只说说我怎么处理装置B的。
用了个四维DP,dp[x][a][b][c](a=0~2; b=0~2; c=0~1)表示节点x,选了a装置(0表示不选,1表示装置A,2表示装置B),fa[x]选了b装置,目前边(u,fa[u])的状态为c。
如果c=0,那么u的子节点中一定要有至少一个装上装置B。而对于上述说的装置B的第二种情况,我们也可以用这个一起计算。
那么就是两种方案:
1、u的子节点中至少有一个装上装置B。
2、u的子节点中没有装上装置B的。
当符合条件时,取两者的min值即可。
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 10010 8 #define INF 100000010 9 10 int dp[Maxn][3][3][2]; 11 int first[Maxn],fa[Maxn]; 12 int n,c1,c2; 13 14 struct node 15 { 16 int x,y,next; 17 }t[2*Maxn];int len; 18 19 void ins(int x,int y) 20 { 21 t[++len].x=x;t[len].y=y; 22 t[len].next=first[x];first[x]=len; 23 } 24 25 int mymin(int x,int y) {return x<y?x:y;} 26 27 void dfs(int x,int f) 28 { 29 fa[x]=f; 30 for(int i=first[x];i;i=t[i].next) if(t[i].y!=f) 31 { 32 int y=t[i].y; 33 dfs(y,x); 34 } 35 } 36 37 int ffind(int x,int a,int b,int c)// a->x b->fa c->(x,fa[x]) 38 { 39 if(dp[x][a][b][c]<INF) return dp[x][a][b][c]; 40 int ans=dp[x][a][b][c]; 41 int p=(a!=0||b==2)?1:0,h=0,y,now; 42 for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x])//sons have at least one B 43 { 44 y=t[i].y; 45 now=mymin(mymin(ffind(y,0,a,1),ffind(y,1,a,1)),ffind(y,2,a,1)); 46 h+=now; 47 } 48 for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]) 49 { 50 y=t[i].y; 51 now=mymin(mymin(ffind(y,0,a,1),ffind(y,1,a,1)),ffind(y,2,a,1)); 52 ans=mymin(ans,h-now+ffind(y,2,a,1)); 53 } 54 if(c!=0) //sons have no B 55 { 56 now=0; 57 for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]) 58 { 59 y=t[i].y; 60 now+=mymin(ffind(y,0,a,p),ffind(y,1,a,1)); 61 } 62 ans=mymin(ans,now); 63 } 64 if(a==1) ans+=c1; 65 else if(a==2) ans+=c2; 66 dp[x][a][b][c]=ans; 67 return ans; 68 } 69 70 int main() 71 { 72 while(1) 73 { 74 scanf("%d%d%d",&n,&c1,&c2); 75 if(n==0&&c1==0&&c2==0) break; 76 len=0; 77 memset(first,0,sizeof(first)); 78 for(int i=1;i<n;i++) 79 { 80 int x,y; 81 scanf("%d%d",&x,&y); 82 ins(x,y);ins(y,x); 83 } 84 memset(dp,63,sizeof(dp)); 85 dfs(1,0); 86 int ans=INF; 87 ans=mymin(ans,ffind(1,0,0,1)); 88 ans=mymin(ans,ffind(1,1,0,1)); 89 ans=mymin(ans,ffind(1,2,0,1)); 90 printf("%d\n",ans); 91 } 92 return 0; 93 }
2016-03-10 17:16:10