hdu 3094 树的删边游戏
A tree game
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 383 Accepted Submission(s): 180
一、链的删边游戏
游戏规则:对于一条链,两人轮流删边,脱离根的部分byebye,没边可删的人,输。
这个,应该很简单。那么,它的sg究竟怎么回事捏?
当只有一个根存在时,先手必败。
当有2个结点时,如图:
所以,红点的sg=1。
当有3个结点时,如图:
所以,红点的sg=2。
依次类推。
链表的sg就这么简单。
二、树的删边游戏
游戏规则:对于一棵树,两人轮流删边,脱离根的部分byebye,没边可删的人,输。
有了链后,我们看树,其实,就是一个组合游戏。
于是乎,很明显,这成了一个Nim游戏的组合。
所以,在树中,叶子结点的sg=0,其他节点的sg等于儿子结点的sg+1的异或和。
三、局部连通图的删边游戏
游戏规则:在一个局部连通图上,两人轮流删边,脱离根的部分byebye,没边可删的人,输。局部连通图的构图规则是,在一棵基础树上加边得到,所有形成的环保证不共用边,且只与基础树有一个公共点。
如图,是一个局部连通图:
因为这些环都是单独悬浮在一棵树上的某些点的。我们单独考虑环。
对于一个独立的偶环而言,根在偶环上,一定有先手必败。
原因是,先手删去偶环上的仪表边后,根有了两条链,链的长度一定为一奇一偶,既长短不一,后手只需要把长的那条链转移成合短的那条链长度一样即可。这样,先手必输,根的sg=0。
对于一个独立的奇环而言,根在奇环上,一定有先手必胜,根的sg=1。
原因是,先手删去某条边后,可以保证根结点连接的两条链的长度一样长。这样,先手必胜。
现在把环带进局部连通图中,那些环上的红点就相当于环的根。对于整个图,我们只需要无视所有偶环,把奇环换成一条边。
如上面的图,按照这个规则变后,就是:
这个时候,又转成了树的删边游戏。
用vector二维容器存储两两顶点之间的关系递归深搜
代码:
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
vector<int> v[100005];
int sg[100005];
bool vis[100005];
int mex(int n)
{
int i;
if(sg[n]!=-1)
return sg[n];
sg[n]=0;
vis[n]=true;
for(i=0;i<v[n].size();i++)
if(!vis[v[n][i]])
sg[n]^=(mex(v[n][i])+1);
vis[n]=false;
return sg[n];
}
int main()
{
int t,a,b,i,n;
cin>>t;
memset(vis,false,sizeof(vis));
while(t-- && scanf("%d",&n))
{
memset(sg,-1,sizeof(sg));
for(i=1;i<=n;i++)
v[i].clear();
for(i=1;i<n;i++)
{
scanf("%d %d",&a,&b);
v[a].push_back(b);
v[b].push_back(a);
}
if(mex(1))
printf("Alice\n");
else
printf("Bob\n");
}
return 0;
}