UVA - 1218 Perfect Service (树形dp)(inf相加溢出)
题意:给你一个树形图,让你把其中若干个结点染成黑色,其余的染成白色,使得任意一个白色结点都恰好与一个黑色结点相邻。
解法比较容易,和树上的最大独立集类似,取一个结点作为树根,对每个结点分三种情况讨论即可:自己是黑色,自己是白色而父亲是黑色,自己和父亲都是白色。
但关键在于这道题如果用inf来作为不合法状态的dp值的话,会导致在dp的过程中有多个inf相加而炸掉!!习惯把inf设成0x3f3f3f3f或者0x7fffffff的选手们要杯具了。
解决方法有很多,比如把inf设小一点,把int改成longlong等等都可以。比较保险的方法是在运算的过程中如果超过inf就立即改成inf,这样只要保证两个inf相加不会溢出就行了,这时候0x3f3f3f3f的好处就体现出来了,两个0x3f3f3f3f相加之后仍不超过int上限。
这是我第一次爆inf的经历,为什么其他的题都不爆inf,偏偏在这道题上爆了呢?我也想不出一个比较中肯的解释,大概是inf的存在就是为了简化判断,而本身没什么实际意义吧,因此会出现不可预料的结果应该也是正常的,引以为戒。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e4+10,inf=0x3f3f3f3f; 5 struct E {int v,nxt;} e[N<<1]; 6 int n,d[N][3],hd[N],ne; 7 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 8 void dp(int u,int fa) { 9 for(int i=hd[u]; ~i; i=e[i].nxt) { 10 int v=e[i].v; 11 if(v==fa)continue; 12 dp(v,u); 13 } 14 d[u][0]=1,d[u][1]=0,d[u][2]=inf; 15 for(int i=hd[u]; ~i; i=e[i].nxt) { 16 int v=e[i].v; 17 if(v==fa)continue; 18 d[u][0]+=min(d[v][0],d[v][1]); 19 d[u][0]=min(d[u][0],inf); 20 } 21 for(int i=hd[u]; ~i; i=e[i].nxt) { 22 int v=e[i].v; 23 if(v==fa)continue; 24 d[u][1]+=d[v][2]; 25 d[u][1]=min(d[u][1],inf); 26 } 27 for(int i=hd[u]; ~i; i=e[i].nxt) { 28 int v=e[i].v; 29 if(v==fa)continue; 30 d[u][2]=min(d[u][2],d[u][1]+d[v][0]-d[v][2]); 31 d[u][2]=min(d[u][2],inf); 32 } 33 } 34 35 int main() { 36 while(scanf("%d",&n)==1) { 37 memset(hd,-1,sizeof hd),ne=0; 38 for(int i=1; i<n; ++i) { 39 int u,v; 40 scanf("%d%d",&u,&v); 41 addedge(u,v); 42 addedge(v,u); 43 } 44 dp(1,-1); 45 printf("%d\n",min(d[1][0],d[1][2])); 46 int ff; 47 scanf("%d",&ff); 48 if(ff==-1)break; 49 } 50 return 0; 51 }