数学:博弈论-树上删边游戏

可以说成是树上的NIM游戏嘛

POJ3710

再树上删边,树是带环的,然后基本题意还是和NIM游戏一致

按环分类讨论,如果是奇数环

所有后继SG值都会是偶数,所以这个状态SG为1

把环缩成一个点+1条边

如果是偶数环,那么后继SG非0,此环SG=1,就将环缩为1个点

对于环,利用tarjan+栈预处理

 1 #include<cstdio>
 2 #include<cstring>
 3 const int maxn=1005;
 4 int n,m,top,cnt;
 5 bool vis[maxn],ve[maxn];
 6 int g[maxn],w[maxn],s[maxn];
 7 struct Edge
 8 {
 9     int t,next;
10 }e[maxn*2];
11 void insert(int u,int v)
12 {
13     cnt++;e[cnt].t=v;e[cnt].next=g[u];g[u]=cnt;
14     cnt++;e[cnt].t=u;e[cnt].next=g[v];g[v]=cnt;
15 }
16 int dfs(int x)
17 {
18     vis[x]=1;
19     int ans=0;
20     s[++top]=x;
21     for(int tmp=g[x];tmp;tmp=e[tmp].next)
22     {
23         if(!ve[tmp])
24         {
25             ve[tmp]=1;ve[tmp^1]=1;
26             int temp;
27             if(!vis[e[tmp].t]) temp=dfs(e[tmp].t)+1;
28             else
29             {
30                 int q=s[top--];
31                 while(q!=e[tmp].t)
32                 {
33                     w[q]=1;
34                     q=s[top--];
35                 }
36                 ++top;
37                 return 1;
38             }
39             if(w[e[tmp].t]) ans^=(temp)%2;
40             else ans^=temp;
41         }
42     }
43     return ans;
44 }
45 int main()
46 {
47     int T,ans,x,y;
48     while(scanf("%d",&T)==1)
49     {
50         ans=0;
51         while(T--)
52         {
53             memset(g,0,sizeof(g));
54             memset(vis,0,sizeof(vis));
55             memset(ve,0,sizeof(ve));
56             memset(w,0,sizeof(w));
57             top=0;cnt=1;
58             scanf("%d%d",&n,&m);
59             for(int i=0;i<m;i++)
60             {
61                 scanf("%d%d",&x,&y);
62                 insert(x,y);
63             }
64             ans^=dfs(1);
65         }
66         if(ans) puts("Sally");
67         else puts("Harry");
68     }
69     return 0;
70 }
原文地址:https://www.cnblogs.com/aininot260/p/9580087.html