SGU 520 Fire in the Country 博弈SG函数(或者YY一下)

来源:互联网 发布:最新版学越南语软件 编辑:程序博客网 时间:2024/05/17 06:47

题目大意:
现在给出一个有着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;}


0 0
原创粉丝点击