POJ 3710 Christmas Game

POJ_3710

    一开始学SG函数的时候,还是单纯地认为一个公平组合游戏都很轻松的变成一个有向图上的来回移动几个棋子的游戏,但是这个题我不管怎么化归都化归不过去了。

    后来纠结了一段时间之后,把《Game Theory》这篇论文看了一下,才发现这个题目实际算是一个基础的模型,就像那种如果你见过就很简单,没见过就打死也做不出的题。所以自己也突然感觉到SG函数的题目还是很有必要积累一些基础的模型的。

    这个题目具体的做法在《Game Theory》上面都有说,所以还是推荐大家阅读一下这篇论文,很多中文的讲SG函数的文章都是翻译的这篇论文里面的内容。这个论文可以在杭电讲博弈的rar文件里面找到,如果你实在找不到的话可以留言,我会发到你的邮箱的。

#include<stdio.h>
#include<string.h>
#define MAXD 110
#define MAXM 1010
int T, N, M, e, first[MAXD], next[MAXM], v[MAXM], d[MAXD], dfn[MAXD], low[MAXD], cnt;
void add(int x, int y)
{
v[e] = y;
next[e] = first[x];
first[x] = e;
++ e;
}
void dfs(int x, int pre)
{
int i, j, k;
low[x] = dfn[x] = ++ cnt;
for(i = first[x]; i != -1; i = next[i])
if(v[i] != pre)
{
if(!dfn[v[i]])
{
dfs(v[i], x);
if(low[v[i]] < low[x])
low[x] = low[v[i]];
}
else if(dfn[v[i]] < low[x])
{
low[x] = dfn[v[i]];
d[v[i]] ^= (dfn[x] - dfn[v[i]]) % 2 ? 0 : 1;
}
}
}
int getsg(int x, int pre)
{
int i, j, k, h[MAXD], rear = 0, ans = d[x];
for(i = first[x]; i != -1; i = next[i])
if(v[i] != pre && low[v[i]] == dfn[v[i]])
h[rear ++] = getsg(v[i], x) + 1;
for(i = 0; i < rear; i ++)
ans ^= h[i];
return ans;
}
void solve()
{
int i, j, k, t, x, y, z, ans = 0;
for(t = 0; t < T; t ++)
{
scanf("%d%d", &N, &M);
memset(first, -1, sizeof(first[0]) * (N + 1));
e = 0;
for(i = 0; i < M; i ++)
{
scanf("%d%d", &x, &y);
add(x, y), add(y, x);
}
memset(d, 0, sizeof(d[0]) * (N + 1));
memset(dfn, 0, sizeof(dfn[0]) * (N + 1));
cnt = 0;
dfs(1, -1);
ans ^= getsg(1, -1);
}
if(ans)
printf("Sally\n");
else
printf("Harry\n");
}
int main()
{
while(scanf("%d", &T) == 1)
{
solve();
}
return 0;
}


原文地址:https://www.cnblogs.com/staginner/p/2387839.html