uva1220树的最大独立集(2 )



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



你可能感兴趣的:(c,dp,ACM,poj,uva)