uvaoj1220
poj 3342
做这个题之前,一定要先做poj2342 ,因为这个题是只是多了 输入,与输出的条件,较繁琐,所以想练一下思想的一定要先做poj2342!
这个题首先要处理好 输入(存值+判重)
判断情况是否唯一(被拌了好长时间。。。)
因为有两种状态 :(书上写的很清楚)
1.结点u 和 它的子节点的子节点集 (gs --> dp[][0])
2. 结点u的子节点集 (s ---> dp[][1])
判断情况是否唯一: (判断 与与求最大大数一样,只要注意 f 与 gs ,s对应关系就行啦)
只要 gs[i]+1 == s[i] ,说明可以取这两种情况的任意一种,那么就是不唯一
但是,更重的是怎么把它继续传下去?
由于 i 的父节点 和 父父结点都可能取到它 ,那么一但用到i结点,那么它选取与
多种情况的结点 结合,那么它也就具有情况不唯一的特点,并继续把它传下去
这种是按层次顺序的递推,倒着推的。
for( i = maxl;i >=0 ;i--) //从最底层开始向上推 for( j = 0;j < ans;j++) if(lev[j] == i) { dp[j] = max(gs[j]+1 ,s[j]); if(gs[j]+1 == s[j] ) //该节点取值不唯一 { if(i>=1) f[par[j]][0] = 1; if(i>=2) f[par[par[j]]][1] = 1; } else if(gs[j]+1 < s[j]) { if(f[j][0] && i>=1) // 因为该节点 选取组合的子节点情况不唯一,则该节点也是情况不唯一 f[par[j]][0] = 1; } else { if(f[j][1] && i>=2) //同理 ,一定要注意选取的子结点与子节点本身取值情况是对应的 f[par[par[j]]][1] = 1; } }
递推,注意一定要有层次结构,那么在这里就要构造了,构造一个数组,专门用来存结点所在的层次
f[ ][ 0 ] 与 s[ ] 对应
f[ ][ 1 ] 与 gs[ ] 对应
#include<stdio.h> #include<string.h> #define max(a,b) a>b?a:b int ve[210][210]; char name[210][300]; int par[210],lev[210],maxl; int ans; int gs[210],s[210],dp[210],f[210][2]; void wr(int n) { int i,j1,j2; memset(par,-10,sizeof(par)); memset(lev,0,sizeof(lev)); for( i = 0;i<n;i++) { scanf("%s",&name[ans++]); scanf("%s",&name[ans++]); for(j1 = 0;j1<ans-2;j1++) if( strcmp(name[j1],name[ans-2])== 0)break; for(j2 = 0;j2<ans-2;j2++) if( strcmp(name[j2],name[ans-1])== 0)break; if(j1!=ans-2 && j2!=ans-2) { ans -= 2; } else if(j1 !=ans -2 && j2 ==ans-2) { strcpy(name[ans-2],name[ans-1]); ans--; } else if(j1 ==ans -2 && j2 != ans-2) { ans--; } else { j2++; } ve[j1][j2] = 1; ve[j2][j1] = 1; } } void dfs(int u,int fa) // 构造了两个关系 { int i; if( fa == -1) lev[u] = 0; else { lev[u] = lev[fa]+1; maxl = max(lev[u] ,maxl); } for(i = 0;i<ans;i++) if(ve[u][i] == 1 && par[i]< -2 ) { par[i] = u; dfs(i , u); } } int main() { int i,j,y; int n; while(1) { memset(ve,0,sizeof(ve)); scanf("%d",&n); if(n == 0)break; n--; scanf("%s",&name[0]); ans = 1; wr(n); maxl = 0; par[0] = -1; dfs(0, -1); memset(gs,0,sizeof(gs)); memset( s,0,sizeof( s)); memset(dp,0,sizeof(dp)); memset(f,0,sizeof(f)); for( i = maxl;i >=0 ;i--) //递推 for( j = 0;j < ans;j++) if(lev[j] == i) { dp[j] = max(gs[j]+1 ,s[j]); if(gs[j]+1 == s[j] ) //判断并传递 组合种类的情况 { if(i>=1) f[par[j]][0] = 1; if(i>=2) f[par[par[j]]][1] = 1; } else if(gs[j]+1 < s[j]) { if(f[j][0] && i>=1) f[par[j]][0] = 1; } else { if(f[j][1] && i>=2) f[par[par[j]]][1] = 1; } if(i - 1>=0) //就这几行是递推的每个节点的两种组合情况 { s[ par[j] ] += dp[j]; } if(i - 2>=0) { gs[ par[par[j]] ] += dp[j]; } } if(n== 0) //知道了递推的顺序,由于时 结点推得上面的结点,所以最后跟的结点要自己再判断自身 printf("%d Yes\n",dp[0]); else if((gs[0]+1 == s[0])||( gs[0]+1 > s[0] && f[0][1])||( gs[0]+1 < s[0] && f[0][0])) printf("%d No\n",dp[0]); else printf("%d Yes\n",dp[0]); } return 0; }
dfs 较方便,有些地方改了,是基于poj2342写的, dp【】【0】 相当于 s 【】 ,dp【】【1】 相当于 gs【】 +1
在这里,我是由于方便 直接初始dp【】【1】 = 1 ,方便. 相当于gs【】 初始就是1,在累加的时候就不用 再 +1 了。
#include<stdio.h> #include<string.h> #define max(a,b) a>b?a:b char name[205][200]; char a[200]; int ans; int dp[205][2] , par[205],f[205][2]; int check() { int i; for(i = 0;i<ans;i++) if(strcmp( a ,name[i]) == 0)return i; strcpy(name[ans++],a); return ans- 1 ; } void dfs(int r) { int i,m; for( i = 1; i <ans; i++) { if(par[i] == r) { dfs(i); m = max(dp[i][0] ,dp[i][1]); dp[r][0] += m; if(par[r]!=-1) dp[ par[r] ][1] += m; if(dp[i][0] == dp[i][1] ) { f[r][0] = 1; if(par[r]!=-1) f[par[r]][1] = 1; } else if(dp[i][1] < dp[i][0]) { if(f[i][0]) f[r][0] = 1; } else { if(f[i][1] && r != 0 ) f[par[r]][1] = 1; } } } } int main() { int n,i; int c,fr; while(scanf("%d",&n)) //不知道什么情况 如果写成 whlie(~scanf("%d",&n))就 WA 了,,, { if(n == 0) break; memset(dp,0,sizeof(dp)); memset(par,0,sizeof(par)); memset(f,0,sizeof(f)); scanf("%s",&name[0]); ans = 1; par[0]= -1; for( i = 1;i< n;i++) { scanf("%s",&a); c = check(); scanf("%s",&a); fr = check(); par[c] = fr; dp[c][1] = 1; dp[fr][1] = 1; } dfs(0); if(n== 1) printf("1 Yes\n"); else if((dp[0][0] == dp[0][1])||( dp[0][0]<dp[0][1] && f[0][1])||( dp[0][0]>dp[0][1] && f[0][0])) printf("%d No\n",max(dp[0][0] , dp[0][1])); else printf("%d Yes\n",max(dp[0][0] , dp[0][1])); } return 0; }
语言表达能力有限,看是看代码吧。
给几组数据
6
A
B A
F C
D A
E A
C A
6
A
B A
C A
F C
D A
E A
4 NO
4 NO