http://acm.hdu.edu.cn/showproblem.php?pid=6105
这道题真的很不错qwq
alice和bob在一个图上玩游戏,bob的技术是,每次到达一个点,就把他邻接的其他点和这个点都染成黑色,而alice则只能染一个色,并且bob是qq会员,可以删除k跳图的边(想啥时候删啥时候删,事实上二人都是老成谋国之人,都是走的最优解,并且也没有同时删除边的数量限制,所以与时间无关。),也就是改变他们的邻接关系啦。问你谁能获胜qwq。
1 如果bob可以把图分为 两个对应的点, 那么他就能染赢。(每个都能完成克制qwq)
而能分成 两个对应的点,要求两种情况
1 一个点不能有大于等于2的 奇数分支。。。(有就分不了。)
)。
2 数量等于偶数。
而 在奇数的点 的情况下,alice每次取 叶子节点的父节点。就能赢。
所以分为以下情况
1 图有 二以上的分叉点, alice赢。
2 图点为 奇数 alice赢。
3 图点为 偶数 且bob可以切割的数量足够 且上图的条件都不成立,bob终于赢了。
4 bob切割力量不够,最后不得不保留一个奇数大小 的子图,被alice血虐,或者自己切割了一个孤立的点。。
(两种不能匹配的情况)
红色标记 bob想切割的图,如此,则大事尚可为,不然就要别虐。(alice选定叶子节点的父亲。。就这一招。)
(官方题解,说的更好一点。)
#include <bits/stdc++.h>
using namespace std;
/* alice的策略是,每次都在夜子节点的父节点搞一搞,
这样,bob就会被制衡,必须在这个叶子节点,
而如果有一个节点的siz大于等于2,那么bob小伙子就无法赢。
因为,这样alice染大于2的节点,那么就可以保留一个孤立的点
2 如果没有siz大于2并且节点数目为奇数的,那么就染叶子的节点的父节点,
3 如果siz大于2
dfs1 是错的。2
12 1000
3 4 5 1 2 8 9 4 11 12 4
这个数据。
*/
const int maxn=1e4;
vector<int>G[maxn];
int size[maxn];
int flag;
void dfs(int u)
{
int num=0;
size[u]=1;
for(int i=0;i<G[u].size();i++)
{
int to=G[u][i];
dfs(to);
size[u]+=size[to];
if(size[to]%2==1)num++;
}
if(num>=2)flag=1;
}
/*
*/
int dfs1(int m){
int ans=0;
for(int i=0;i<G[m].size();i++){
ans+=dfs1(G[m][i]);
if(ans>=2) {flag=1;
//cout<<"!!!!!"<<m<<endl;
return 0;}//不存在两两配对
}
if(G[m].size()==0)
return 1;
return 0;
}
int main()
{ freopen("f:\\ttt\\1010.txt","r",stdin);
freopen("f:\\ttt\\out1.txt","w",stdout);
int t;
int m,k,x;
scanf("%d",&t);
while(t--){
memset(size,0,sizeof(size));
for(int i=0;i<maxn;i++)
G[i].clear();
scanf("%d%d",&m,&k);
for(int i=2;i<=m;i++){
scanf("%d",&x);
G[x].push_back(i);
}
flag=-1;
/*for(int i=0;i<=m;i++){
if(G[i].size()>2)
flag=true;
}*/
dfs(1);
//if(flag!=-1)
//cout<<flag<<endl;
//flag=-1;
if(m%2==1)
flag=1;//不存在两两配对
if(m%2==0){
if(k>=m/2-1&&flag==-1)
{ //cout<<"flag"<<flag<<endl;
flag=0;}
else flag=1;
}
if(flag==1)
puts("Alice");
else if(flag==0)
puts("Bob");
}
return 0;
}