Ayush and Ashish在玩一个游戏:每轮中,每个玩家可以在一棵无根树上拆掉一个叶节点和从该节点出发的一条边(实际上就是让你拆点的时候拆的全面一点 )。当有人拆到指定结点为获胜。现在给出这个无根树的拓扑结构,求这局谁赢。
这个题我第一感觉就像在问:公交车第一站上8个下2个,第二站上3个下5个,问公交车司机姓什么?
这个问法显然是存在必胜策略,如果先手赢,那么最后一定是
如果获胜必然要拆除指定结点(root)相连的点,因此可以将原无根树描述如下
在这里将节点数最多的一条分支作为一部分maxcomponent,其余的作为另一部分elsecomponent。
首先从elsecomponent开始拆,不难得出
elsecomponent % 2 == 0 先手胜
elsecomponent % 2 == 1 后手胜
拆完这块再去拆maxcomponent,胜负情况相同。最后列举所有排列就可以了。
那么是否存在别的策略能在必败局中取胜呢?impossible。无论先手从哪部分拆,后手只要在同一部分跟随,就能保证奇偶性,从而保证必胜。
需要注意的是当root一开始就处于叶结点时特判
直到写完才发现,好像直接用 (n-1)%2 判断就可以
#pragma GCC diagnostic error "-std=c++11"
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return
#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
template<class T> void _deb(const char *name,T val){
cout<<name<<val<<endl;
}
const int maxn=1024;
int t;
bool vis[maxn];
int numOfnode[maxn];
vector<int> adj[maxn];
int dfs(int node);
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>t;
while(t--){
int n,root;
cin>>n>>root;
rep(i,1,n+1){
numOfnode[i]=0;
vis[i]=false;
adj[i].clear();
}
rep(i,1,n){
int a,b;
cin>>a>>b;
adj[a].Push(b);
adj[b].Push(a);
}
if(getLen(adj,root)<=1){
cout<<"Ayush"<<endl;
continue;
}
dfs(root);
int maxComponent=-1,elseComponent;
rep(i,0,getLen(adj,root)){
int &node=adj[root][i];
maxComponent=max(maxComponent,numOfnode[node]);
}
elseComponent=numOfnode[root]-maxComponent-1;
bool judge1=elseComponent%2,judge2=maxComponent%2;
if(judge1^judge2){
cout<<"Ayush"<<endl;
}else{
cout<<"Ashish"<<endl;
}
}
re 0;
}
int dfs(int node){
vis[node]=true;
int sum=1;
rep(i,0,getLen(adj,node)){
int &nextNode=adj[node][i];
if(!vis[nextNode])
sum+=dfs(nextNode);
}
re numOfnode[node]=sum;
}