[NIM博弈]矿物运输

荒凉一梦 提交于 2019-12-04 00:53:07

题目限制
1500 ms 128 M

题目描述
在某个不知名的行星上蕴含着大量冰晶矿,Jim和他的好兄弟Swan自然不能放过这个赚钱的好机
会。Jim在整个星球上开掘树型矿洞,每个矿坑之间都有矿道相连。Jim和Swan在每个矿坑开采了
大量的矿石,现在他们面临一个新的问题,怎么把所有的矿石运出去。
已知,矿坑与矿坑之间形成了有向的树形结构,即除0号矿坑以外每个矿坑都有与其相连的父亲矿
坑。Jim总共开采了  n个矿坑并将其从0到 n-1  编号 ,每个矿坑都存有   val[i]个单位的矿石。
Jim和Swan每次操作都可以从某个矿坑移动至少1个单位的矿石到其父亲矿坑。Jim和Swan决定比
试一下,由Jim开始轮流操作,最后不能操作的人输。Jim偷偷的找到了你,他想知道在两人都采取
最优策略的情况下是否Jim能够赢得这场比试。
输入格式
多组数据
第一行为数据组数,T <=30
第二行一个整数n,表示矿坑数目,n<=2e5
接下来一行为n-1个整数fa[1]..fa[n-1],分别描述了除根节点外每个点的父亲。方便起见,保证

0<=fa[i]<i。
接下来一行为n个非负整数val[0]..val[n-1],分别描述了每个矿坑初始的矿石数。0<=val[i]<1e9。

输出格式
对于每组数据,输出一行,若Jim必胜则输出"win",否则输出"lose"(不含引号)。

数据范围
对于 25%的数据 保证 n<=10
对于 50%的数据 保证 n<=1000
存在 10%的数据 每个矿坑只有一个子矿坑
存在 10%的数据 除0号矿坑外,每个矿坑都与0号矿坑相连。
对于 100%的数据 保证 n<=200000

输入样例
1
6
0 0 2 2 4  
1 4 0 1 1 2
输出样例
win

NIM博弈讲解 https://www.luogu.org/problemnew/solution/P2197

                      https://www.iteye.com/blog/huobengle-1386808

多个有向图(G)游戏的
和SG函数值等于它包含的各个子游戏SG函数值的异或和,即SG(G) = SG(G1) xor SG(G2) xor …
SG(Gm)。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N=200005;
 5 int n,fa[N],val[N],sum;
 6 int num,last[N],nxt[N],ver[N];
 7 inline void add(int x,int y) {nxt[++num]=last[x]; last[x]=num; ver[num]=y;}
 8 void dfs(int x,int dep)
 9  {if(dep&1) sum^=val[x];
10   for(int i=last[x];i;i=nxt[i])
11    {int y=ver[i];
12     dfs(y,dep+1);
13    }
14  }
15 int main()
16  {
17  freopen("ore.in","r",stdin);
18  freopen("ore.out","w",stdout);    
19  int t; scanf("%d",&t);    
20      
21  while(t--)    
22   {scanf("%d",&n); 
23    num=sum=0; memset(last,0,sizeof(last));
24    
25    for(int i=2;i<=n;i++) 
26     {scanf("%d",&fa[i]); fa[i]++; add(fa[i],i); } 
27    for(int i=1;i<=n;i++) scanf("%d",&val[i]);  
28    dfs(1,0); 
29    if(sum) printf("win\n");
30    else    printf("lose\n");
31   }         
32      
33      
34 return 0;
35  }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!