SGU 520 Fire in the Country 博弈SG函数(或者YY一下)
2014-09-03 11:44
369 查看
题目大意:
现在给出一个有着n个顶点m条边的图,边为双向边, 现在两个人轮流操作机器人,机器人从点1开始走,两个人轮流控制机器人走向与当前点相连的点,两个人每次操作机器人走的同时,火势将会向外蔓延,每操作一次之后火势就向与当前着火点相连的点蔓延,机器人在谁操作之后被火烧到谁就输,比如样例:
Nikolay先手从1走到3,当天晚上1着火,然后Vladimir只能从3走到1,当天晚上1是着火点所以Vladimir输了,输出Vladimir
大致思路:
这题比赛的时候想的是一个YY的做法:
我定义P点:一个点是P点当且仅当谁控制机器人走到这个点谁就赢
相反的是N点:一个点是N点表示谁控制机器人走到这个点谁就输
由于火势是不停蔓延的,那么控制机器人行动时不能回头,这样即使图中有环,也不可能往回走,可以先BFS遍历一下找到点的层级( 即到达该点的步数 ) 这样我们就只能控制机器人从层级低的点走到层级高的点,这样原图可以变成一个无环有向图,图的边来自于原图中层级低的点指向层级高的点且在原图中连通
我们考虑父亲结点root和子节点son[ i ] ( 这里就是拓扑序的意思,方编写我就当做树的层级吧..虽然可能不是树...) ,当父亲节点没有子节点时,一定是 P 点,因为下一个人已经无路可走了
当父亲节点有子节点时,如果子节点中有P点,那么父亲节点是N点( 博弈中的小策略 )也很容易明白因为代打这个父亲节点后,下一个人一定会选择走到P点这样走到这个父亲节点的人就输了,也就是说只需要判断父亲节点的子节点中有无P点即可判断父亲节点是P点还是N点
这样dfs一下找到节点1的值是P还是N即可,是N则Vladimir赔钱,否则Nikolay赔钱
比赛之后学了一些图上的博弈,发现这题可以用Sprague-Grundy函数来解和之前一样BFS建好新的无环有向图之后,用dfs迭代求SG函数的值
当SG[ 1 ] == 0 时,Nikolay赔钱,SG[ 1 ] != 0时,Vladimir赔钱
这里附上SG函数解法的代码(相比上一种比赛时YY出来的方案感觉还是好一点)
题解写一半发现CSDN维护了..我擦...
Result : Accepted Memory : 322 KB Time : 15 ms
/*
* Author: Gatevin
* Created Time: 2014/9/2 22:10:56
* File Name: C.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define pb(x) push_back(x)
#define clr(x) memset(x, 0, sizeof(x))
int n,m;
int deep[1010];//到达对应的点需要走的步数
bool vis[1010];//用了两次,都是用来记忆化
vector <int> G[1010];//原图
vector <int> F[1010];//删边之后的博弈求SG函数用图
queue <int> q;
int SG[1010];
void bfs()
{
clr(vis);
vis[1] = 1;
q.push(1);
while(!q.empty())
{
for(unsigned int i = 0; i < G[q.front()].size(); i++)
{
if(!vis[G[q.front()][i]])
{
deep[G[q.front()][i]] = deep[q.front()] + 1;
vis[G[q.front()][i]] = 1;
q.push(G[q.front()][i]);
}
}
q.pop();
}
return;
}
void build()
{
for(int i = 1; i <= n; i++)
{
for(unsigned int j = 0; j < G[i].size(); j++)
{
if(deep[i] < deep[G[i][j]])
{
F[i].pb(G[i][j]);
}
}
}
return;
}
bool check(int val, int root)//求mex()
{
for(unsigned int i = 0; i < F[root].size(); i++)
{
if(val == SG[F[root][i]]) return true;
}
return false;
}
void dfs(int root)//递归求解SG函数
{
if(F[root].empty())
{
SG[root] = 0;
return;
}
if(vis[root]) return;
for(unsigned int i = 0; i < F[root].size(); i++)
{
dfs(F[root][i]);
}
int cnt = 0;
while(check(cnt, root))
{
cnt++;
}
SG[root] = cnt;
vis[root] = 1;
return;
}
int main()
{
scanf("%d %d", &n, &m);
int tx,ty;
for(int i = 1; i <= m; i++)
{
scanf("%d %d", &tx, &ty);
G[tx].pb(ty);
G[ty].pb(tx);
}
bfs();
build();
clr(vis);
dfs(1);
if(SG[1] != 0)
{
printf("Vladimir\n");
}
else
{
printf("Nikolay\n");
}
return 0;
}
现在给出一个有着n个顶点m条边的图,边为双向边, 现在两个人轮流操作机器人,机器人从点1开始走,两个人轮流控制机器人走向与当前点相连的点,两个人每次操作机器人走的同时,火势将会向外蔓延,每操作一次之后火势就向与当前着火点相连的点蔓延,机器人在谁操作之后被火烧到谁就输,比如样例:
Nikolay先手从1走到3,当天晚上1着火,然后Vladimir只能从3走到1,当天晚上1是着火点所以Vladimir输了,输出Vladimir
大致思路:
这题比赛的时候想的是一个YY的做法:
我定义P点:一个点是P点当且仅当谁控制机器人走到这个点谁就赢
相反的是N点:一个点是N点表示谁控制机器人走到这个点谁就输
由于火势是不停蔓延的,那么控制机器人行动时不能回头,这样即使图中有环,也不可能往回走,可以先BFS遍历一下找到点的层级( 即到达该点的步数 ) 这样我们就只能控制机器人从层级低的点走到层级高的点,这样原图可以变成一个无环有向图,图的边来自于原图中层级低的点指向层级高的点且在原图中连通
我们考虑父亲结点root和子节点son[ i ] ( 这里就是拓扑序的意思,方编写我就当做树的层级吧..虽然可能不是树...) ,当父亲节点没有子节点时,一定是 P 点,因为下一个人已经无路可走了
当父亲节点有子节点时,如果子节点中有P点,那么父亲节点是N点( 博弈中的小策略 )也很容易明白因为代打这个父亲节点后,下一个人一定会选择走到P点这样走到这个父亲节点的人就输了,也就是说只需要判断父亲节点的子节点中有无P点即可判断父亲节点是P点还是N点
这样dfs一下找到节点1的值是P还是N即可,是N则Vladimir赔钱,否则Nikolay赔钱
比赛之后学了一些图上的博弈,发现这题可以用Sprague-Grundy函数来解和之前一样BFS建好新的无环有向图之后,用dfs迭代求SG函数的值
当SG[ 1 ] == 0 时,Nikolay赔钱,SG[ 1 ] != 0时,Vladimir赔钱
这里附上SG函数解法的代码(相比上一种比赛时YY出来的方案感觉还是好一点)
题解写一半发现CSDN维护了..我擦...
Result : Accepted Memory : 322 KB Time : 15 ms
/*
* Author: Gatevin
* Created Time: 2014/9/2 22:10:56
* File Name: C.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define pb(x) push_back(x)
#define clr(x) memset(x, 0, sizeof(x))
int n,m;
int deep[1010];//到达对应的点需要走的步数
bool vis[1010];//用了两次,都是用来记忆化
vector <int> G[1010];//原图
vector <int> F[1010];//删边之后的博弈求SG函数用图
queue <int> q;
int SG[1010];
void bfs()
{
clr(vis);
vis[1] = 1;
q.push(1);
while(!q.empty())
{
for(unsigned int i = 0; i < G[q.front()].size(); i++)
{
if(!vis[G[q.front()][i]])
{
deep[G[q.front()][i]] = deep[q.front()] + 1;
vis[G[q.front()][i]] = 1;
q.push(G[q.front()][i]);
}
}
q.pop();
}
return;
}
void build()
{
for(int i = 1; i <= n; i++)
{
for(unsigned int j = 0; j < G[i].size(); j++)
{
if(deep[i] < deep[G[i][j]])
{
F[i].pb(G[i][j]);
}
}
}
return;
}
bool check(int val, int root)//求mex()
{
for(unsigned int i = 0; i < F[root].size(); i++)
{
if(val == SG[F[root][i]]) return true;
}
return false;
}
void dfs(int root)//递归求解SG函数
{
if(F[root].empty())
{
SG[root] = 0;
return;
}
if(vis[root]) return;
for(unsigned int i = 0; i < F[root].size(); i++)
{
dfs(F[root][i]);
}
int cnt = 0;
while(check(cnt, root))
{
cnt++;
}
SG[root] = cnt;
vis[root] = 1;
return;
}
int main()
{
scanf("%d %d", &n, &m);
int tx,ty;
for(int i = 1; i <= m; i++)
{
scanf("%d %d", &tx, &ty);
G[tx].pb(ty);
G[ty].pb(tx);
}
bfs();
build();
clr(vis);
dfs(1);
if(SG[1] != 0)
{
printf("Vladimir\n");
}
else
{
printf("Nikolay\n");
}
return 0;
}
相关文章推荐
- SGU 520 Fire in the Country(博弈+搜索)
- sgu - 520 - Fire in the Country(bfs + dfs + 博弈)
- 2010-2011 ACM-ICPC, NEERC, Southern Subregional Contest Fire in the Country(博弈论+搜索)
- 安装scipy或者numpy时弹出python2.7 was not found in the registry 的解决办法: python的注册与注销方法
- No grammar constraints (DTD or XML Schema) referenced in the document. java项目xml文件报错或者出现警告
- “the runtime file is not exists in project”或者“ 工程中不存在runtime文件”
- 20080407 - Fire in the hole
- POJ 3688 Cheat in the Game (博弈 dp)
- 下面三句代码有没有错,以inboxing或者unboxing为例,解释一下内存是怎么变化的
- zoj 2083 Win the Game(博弈SG函数)
- The most happiest country in the world
- CocoaPods报错:The dependency `Alamofire ` is not used in any concrete target
- SGU 407-Number of Paths in the Empire【DP】
- HDU 1847 Good Luck in CET-4 Everybody!(找规律,或者简单SG函数)
- hdu 1847 博弈基础题 SG函数 或者规律2种方法
- SGU 407 Number of Paths in the Empire dp+java大数
- How to setup VVR in VCS , including the FireDrill.
- 介绍一下thefreecountry.com
- hdu 1847 博弈基础题 SG函数 或者规律2种方法
- sgu 1348 Goat in the Garden 2【点到线段的距离】