【Foreign】红与蓝 [暴力]

红与蓝

Time Limit: 10 Sec  Memory Limit: 256 MB

Description

  

Input

  

Output

  

Sample Input

  2
  2
  0 1
  -1 -1
  2
  0 1
  -1 1

Sample Output

  1 2
  -1

HINT

  

Main idea

  每个节点有红色、蓝色或者无色,给定了若干叶子节点的颜色,非叶子节点的颜色定义为所有儿子中颜色出现次数最多的一个,若一样则无色。叶子节点无色则可以染色,红色先手,蓝色接着轮流染色,最后若根为红色则胜利否则失败。胜利的话还要求输出可行方案。

Source

  我们可以先O(n)求出在不动叶子节点情况下每一个点的颜色,由于每个一个点只有奇数个儿子,且红色先手。那么这时候如果根节点为红色或者无色则必胜,蓝色则必败

  然后我们分情况讨论,蓝色就直接输出“-1”,结束即可。如果根是红色的话,显然染色对于答案是没有什么影响的,所以所有无色的叶子节点都可以是解

  现在我们来讨论根无色的情况:我们计算每一个点中儿子的蓝色个数和红色个数,如果一个点是 (蓝色,且蓝色个数=红色个数+1) 或者 (无色,蓝色个数=红色个数)则可以往下递归,找到叶子节点为无色则可以是解。我们来解释一下:

  1. 蓝色,蓝色个数=红色个数+1:如果往下走有可染色的叶子节点,那么必然逼着蓝色接着染,否则蓝色就输了。这个点的颜色就会是:无、蓝、无……由于红色先手,所以最后这个点是可以变成无色的,因为递归做到这里,所以这个点的父亲节点是白色的,然后这个点变为了白色,它的父亲就少了一个蓝色儿子,就变成红色了。

  2. 无色,蓝色个数=红色个数:如果往下走有可染色的叶子节点,那么这一条无色链上都会变成红色的,显然可行。

  这样我们暴力递归往下讨论,就解决了这个问题。

Code

  1 #include<iostream>  
  2 #include<algorithm>  
  3 #include<cstdio>  
  4 #include<cstring>  
  5 #include<cstdlib>  
  6 #include<cmath>  
  7 using namespace std;
  8 
  9 const int ONE = 100005;
 10 
 11 int T;
 12 int n,x,root;
 13 int Val[ONE];
 14 int next[ONE],first[ONE],go[ONE],tot;
 15 int ans_num,Ans[ONE];
 16 
 17 void Add(int u,int v)
 18 {
 19         next[++tot]=first[u];    first[u]=tot;    go[tot]=v;
 20 }
 21 
 22 int get()
 23 { 
 24         int res,Q=1;    char c;
 25         while( (c=getchar())<48 || c>57)
 26         if(c=='-')Q=-1;
 27         if(Q) res=c-48; 
 28         while((c=getchar())>=48 && c<=57) 
 29         res=res*10+c-48; 
 30         return res*Q; 
 31 }
 32 
 33 void Deal_first(int u)
 34 {
 35         for(int e=first[u];e;e=next[e])
 36         {
 37             int v=go[e];
 38             Deal_first(v);
 39             Val[u] += Val[v];
 40         }
 41         if(Val[u] < 0) Val[u] = -1;
 42         else if(Val[u] > 0) Val[u] = 1;
 43 }
 44 
 45 void Dfs(int u)
 46 {
 47         if(!Val[u] && !first[u])
 48         Ans[++ans_num] = u;
 49         
 50         for(int e=first[u];e;e=next[e])
 51         {
 52             int v=go[e];
 53             int tot=0;
 54             for(int i=first[v];i;i=next[i])
 55                 tot+=Val[go[i]];
 56             if(tot==0 || tot==-1) Dfs(v);
 57         }
 58 }
 59 
 60 void Solve()
 61 {
 62         n=get();
 63         tot=0; memset(first,0,sizeof(first));
 64         for(int i=1;i<=n;i++)
 65         {
 66             x=get();
 67             if(!x) root=i;
 68             else Add(x,i);
 69         }
 70         
 71         for(int i=1;i<=n;i++)
 72         {
 73             Val[i]=get();
 74             if(Val[i]==0) Val[i]=1;
 75             else if(Val[i]==1) Val[i]=-1;
 76             else Val[i]=0;
 77         }
 78         
 79         Deal_first(root);
 80         if(Val[root] < 0)
 81         {
 82             printf("-1");
 83             return;
 84         }
 85         else
 86         {
 87             ans_num=0;
 88             if(Val[root]==0) Dfs(root),sort(Ans+1,Ans+ans_num+1);
 89             if(Val[root]==1) for(int i=1;i<=n;i++) if(!Val[i] && !first[i]) Ans[++ans_num]=i;
 90             
 91             printf("%d ",ans_num);
 92             for(int i=1;i<=ans_num;i++)
 93                 printf("%d ",Ans[i]);
 94         }
 95 }
 96 
 97 int main()
 98 {      
 99         T=get();
100         while(T--)
101             Solve(),printf("\n");
102 }
View Code

 

  

 

posted @ 2017-03-05 20:53  BearChild  阅读(337)  评论(0编辑  收藏  举报