1-1 T2 rab(博弈論)
阿新 • • 發佈:2019-01-08
題目描述
給定一棵樹,初始時非葉節點均為無色,葉節點會是紅色、藍色或無色。
小紅和小藍輪流給無色葉子染色(小紅染紅色,小藍染藍色,小紅先染)。所有 葉子染完後,非葉節點的顏色將被逐一確定:一個非葉節點的顏色是它所有兒子的顏 色中出現較多的那個(保證有奇數個兒子)。最後,根是誰的顏色誰就獲勝。
求小紅是否能贏,若能贏,求出第一步選擇哪些葉子能贏。
輸入輸出格式
輸入格式:
第一行一個整數t表示資料組數。
每組資料第一行一個整數n表示節點數。
第二行n個整數,第i個整數fi表示i的父親,保證f1=0。
第三行 n個整數,第 i 個整數 gi 表示 i 的初始顏色(0 表示紅色,1表示藍 色,-1表示無色)。
輸出格式:
每組資料輸出一行。
若小紅能贏,先輸出一個整數 m表示第一步可以選的葉子數,接下來 m個 整數表示那些葉子的編號,從小到大輸出。
若你只知道小紅能贏,你可以只輸 出一行一個整數0。
否則輸出一個整數-1。
輸入輸出樣例
輸入樣例#1: 複製
2
2
0 1
-1 -1
2
0 1
-1 1
輸出樣例#1: 複製
1 2
-1
說明
對於20%的資料,t=1,n≤20。
對於60%的資料,n≤2000。
對於100%的資料,t<=10,n≤100000。
若你只判斷對了勝負,可以獲得該測試點一半的分數。
這個題還是挺有趣的。
首先經過一些思考,可以發現:
最優方案一定是一開始選擇一個葉子染,並且使得它的父親變成
那麼我們可以發現,這樣的點滿足兒子中紅色節點數量=藍色節點數量
此時我們可以將它染成無色,恰好滿足題目的意思(通過一步改變它的顏色)
類似的可以染出紅色和藍色,分別代表雙方必勝的情況
先手必勝當且僅當根節點的顏色為紅色或無色
根節點為紅色時,可以隨便選一個葉子,都是符合要求的
根節點為無色時,分兩種情況:
1.我們可以選擇一個無色兒子染
2.我們可以選擇一個藍色兒子染(必須保證不是葉子,且可以通過一步將它染成無色)
然後就統計出來所有點了,最後排序輸出即可。
程式碼:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
const int N=1e5+5;
int T,n,tot,cnt;
int head[N],to[N],Next[N];
int col[N],leaf[N],q[N],num[N];
inline void addedge(int x,int y){to[++tot]=y;Next[tot]=head[x];head[x]=tot;}
inline void dfs(int x){
if(leaf[x])return;
int cntr=0,cntb=0;
for(int i=head[x];i;i=Next[i]){
int u=to[i];
dfs(u);
if(col[u]==0)cntr++;
else if(col[u]==1)cntb++;
}
num[x]=cntr-cntb;
if(num[x]>0)col[x]=0;
else if(!num[x])col[x]=-1;
else col[x]=1;
}
inline void dfs2(int x){
if(leaf[x]){
if(col[x]==-1)q[++cnt]=x;
return;
}
for(int i=head[x];i;i=Next[i]){
int u=to[i];
if(col[u]==-1)dfs2(u);
else if(col[u]==1&&num[u]==-1)dfs2(u);
else if(leaf[u])dfs2(u);
}
}
int main(){
// freopen("./1-1 T2 data/rab3.in","r",stdin);
// freopen("rab3.out","w",stdout);
T=read();
while(T--){
n=read();tot=0;
for(int i=1;i<=n;i++)head[i]=0,leaf[i]=1;
for(int i=1;i<=n;i++){
int fa=read();
if(fa)addedge(fa,i);
leaf[fa]=0;
}
for(int i=1;i<=n;i++)col[i]=read();
dfs(1);
if(col[1]==0){
cnt=0;
for(int i=1;i<=n;i++)if(leaf[i]&&col[i]==-1)cnt++;
printf("%d ",cnt);
for(int i=1;i<=n;i++)if(leaf[i]&&col[i]==-1)printf("%d ",i);
putchar('\n');
}
else if(col[1]==-1){
cnt=0;
dfs2(1);
printf("%d ",cnt);
sort(q+1,q+cnt+1);
for(int i=1;i<=cnt;i++)printf("%d ",q[i]);
putchar('\n');
}
else printf("-1\n");
}
return 0;
}