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