Fennec VS. Snuke
时间限制: 1 Sec 内存限制: 128 MB
提交: 135 解决: 53
[提交] [状态] [讨论版] [命题人:admin]
题目描述
Fennec and Snuke are playing a board game.
On the board, there are N cells numbered 1 through N, and N−1 roads, each connecting two cells. Cell ai is adjacent to Cell bi through the i-th road. Every cell can be reached from every other cell by repeatedly traveling to an adjacent cell. In terms of graph theory, the graph formed by the cells and the roads is a tree.
Initially, Cell 1 is painted black, and Cell N is painted white. The other cells are not yet colored. Fennec (who goes first) and Snuke (who goes second) alternately paint an uncolored cell. More specifically, each player performs the following action in her/his turn:
Fennec: selects an uncolored cell that is adjacent to a black cell, and paints it black.
Snuke: selects an uncolored cell that is adjacent to a white cell, and paints it white.
A player loses when she/he cannot paint a cell. Determine the winner of the game when Fennec and Snuke play optimally.
Constraints
2≤N≤105
1≤ai,bi≤N
The given graph is a tree.
输入
Input is given from Standard Input in the following format:
N
a1 b1
:
aN−1 bN−1
输出
If Fennec wins, print Fennec; if Snuke wins, print Snuke.
样例输入
7
3 6
1 2
3 1
7 4
5 7
1 4
样例输出
Fennec
提示
For example, if Fennec first paints Cell 2 black, she will win regardless of Snuke's moves.
题意:Fennec和Snuke玩一个游戏,F在第一个点并且第一个点为黑色,S在第N个点并且第N个点为白色,然后给出一些点的相连,两个人轮流选择自己自己的颜色旁边相连并且没有上色的点进行涂色,谁最先没有色可以涂谁就输。问最后谁赢谁输。
题解:先dfs找到1到N这条链中间的下一个点并且保存位置为p,然后从第1个点开始再次dfs,如果遇到p点则停止dfs返回0,然后求dfs到点的和sum,如果sum>n-sum那么F赢,否则S赢。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
vector<int> v[100005];
int p;
int n;
int vis[100005];
int dfs1(int x,int step)
{
vis[x]=1;
if(x==n)
{
int mid=step/2+1+step%2;
if(step==mid)p=x;
return mid;
}
for(int i=0;i<v[x].size();i++)
{
int y=v[x][i];
if(!vis[y])
{
int mid=dfs1(y,step+1);
if(mid && step==mid && !p)
{
p=x;
}
if(mid)return mid;
}
}
return 0;
}
int dfs2(int x)
{
vis[x]=1;
if(x==p)return 0;
int ans=0;
for(int i=0;i<v[x].size();i++)
{
int y=v[x][i];
if(!vis[y])ans+=dfs2(y);
}
return ans+1;
}
int main()
{
int x,y;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
memset(vis,0,sizeof(vis));
dfs1(1,1);
memset(vis,0,sizeof(vis));
int ans=dfs2(1);
printf("%s\n",ans>n-ans?"Fennec":"Snuke");
return 0;
}
题解:整体思路就是尽可能先把对手堵住,让对手无法染色。用bfs从1点和n点轮流开始遍历1-n这条路,直到两个相遇(最优策略,最快堵住对手的方法)。
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
const int N=1e5+10;
vector <int> E[N];
int color[N],cnt[3];
int main(){
ios_base::sync_with_stdio(false);
queue <int> que;
int n,x,y;
cin>>n;
for(int i=1;i<n;i++){
cin>>x>>y;
E[x].push_back(y);
E[y].push_back(x);
}
color[1]=1,color[n]=2;//标记颜色
que.push(1);//1点先手
que.push(n);//n点后手
while(!que.empty()){
int tmp=que.front();
que.pop();
cnt[color[tmp]]++;//记录标记颜色的数量
//遍历相邻的所有点,因为把对手堵住后这些点还是需要染色的.
for(int i=0;i<E[tmp].size();i++){
int v=E[tmp][i];
if(color[v]) continue;
color[v]=color[tmp];
que.push(v);
}
}
//因为1点先手,所以数量相同的时候,1点会输.
if(cnt[2]>=cnt[1]) cout<<"Snuke"<<endl;
else cout<<"Fennec"<<endl;
return 0;
}