http://codeforces.com/gym/101246/problem/D
题意:
给定一个无向有环图,大火从1点开始,每个时间点与它相邻的点也将会着火,现在有两个人轮流操作机器人,机器人从1点出发,每个人每次选择一个点走,谁最后被火烧了谁就输了。
思路:
博弈题。
我们先预处理求出每个点着火的时间点,然后根据时间点重建新图,也就是重新建一个有向无环图,原来图中相连的并且时间点相差1的相连,由时间低的连向时间高的。
接下来我们在新图上求每个点的SG值,SG值为0的点就是叶子结点,这样父亲结点的SG值就可以通过子节点的SG值求出,也就是求mex。
最后我们可以求出根结点的SG值,也就是SG【1】的值。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<cstdio>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn=+; int n, m; int t[maxn];
int SG[maxn];
int vis[maxn]; vector<int> G[maxn];
vector<int> new_G[maxn]; //求时间点
void bfs()
{
memset(t, -, sizeof(t));
queue<int> Q;
Q.push();
t[]=;
while(!Q.empty())
{
int u = Q.front(); Q.pop();
for(int i = ; i < G[u].size(); i++)
{
int v = G[u][i];
if(t[v] != -) continue;
t[v] = t[u] + ;
Q.push(v);
}
}
} //建新图
void re_build()
{
for(int i = ; i <= n; i++)
{
for(int j = ; j < G[i].size(); j++)
{
int v = G[i][j];
if(t[v] == t[i] + )
new_G[i].push_back(v);
}
}
} //求SG
void dfs(int u)
{
if(new_G[u].size() == )
{
SG[u] = ;
return;
}
for(int i = ; i < new_G[u].size(); i++)
{
int v = new_G[u][i];
dfs(v);
} //求mex,也就是父亲结点的SG值
for(int i = ; ;i++)
{
bool flag = false;
for(int j = ; j < new_G[u].size(); j++)
{
if(SG[new_G[u][j]] == i)
{
flag = true;
break;
}
}
if(flag == false)
{
SG[u] = i;
break;
}
}
} int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
// freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n, &m))
{
for(int i = ; i <= n; i++) {G[i].clear(); new_G[i].clear();} for(int i = ; i < m; i++)
{
int u, v;
scanf("%d%d",&u, &v);
G[u].push_back(v);
G[v].push_back(u);
} bfs();
re_build();
dfs();
if(SG[] == ) puts("Nikolay");
else puts("Vladimir");
}
return ;
}