SG函数-博弈论
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SG函数-博弈论相关的知识,希望对你有一定的参考价值。
b:时间限制:1s空间限制:64M题目大意:有一个图有n个点,且有m条通道连通这n个点,其中第1个点的能量永远恒定为0,初始所有点的能量均为0。第i条通道连接着x_i,y_i两个点,而且它两端点的能量之差不会超过c_i。在整个图中有k个能量源,初始的时候能量源均为休眠状态。现在Alice和Bob玩一个游戏,他们轮流进行操作,每次操作可以选择一个能量源激活,在一个能量源被激活的时候,它将会把当前节点的能量尽可能增大,且其他的点的能量会因为通道的连接同时增大。当当前点的能量达到最大值之后(由于点1的限制),操作者需要将其移动到可以使它的能量更大的相邻点,使它进入休眠状态,所有点的能量归0。如果不存在这样的相邻点,那么可以将该能量源摧毁,注意在可以移动时是不能摧毁它的。当图中没有能量源时该玩家输掉这个游戏。问Alice是否有必胜策略。输入格式:本题有多组测试数据。对于每组测试数据,第一行三个数n,m,k。接下来m行,每行三个数x_i,y_i,c_i。接下来一行k个数,表示k个能量源的位置。输出格式:对于每组数据,如果Alice必胜则输出"Alice",否则输出"Bob"(不含引号)。样例输入:4 5 21 2 32 3 21 3 43 4 12 4 11 24 5 31 2 32 3 21 3 43 4 12 4 12 3 4样例输出:AliceBob数据范围:对于10%的数据:n,k <= 8, m <= 20对于另20%的数据:k=1对于60%的数据:n,k <= 200, m <=500对于另20%的数据:k=2对于100%的数据:数据组数 <= 10, n,k <= 20000, m <= 50000, 1 <= c_i <=10000
具体论文可查百度:SG函数、博弈论等关键词。
该游戏的必胜情况为各个子游戏Sg值的异或,
即SG(G)=SG(g1) xor SG(g2) xor……xor SG(gn)
我们定义mex({一个整数集合S})=最小的不在集合S中的正整数
则SG(gn)=mex({SG(gm)|状态gn可以转移到状态gm})
该题标程:(被卡常数,略超1s)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 using namespace std; 8 struct edge{ 9 int to,cap; 10 friend bool operator<(const edge a,const edge b){ 11 return a.cap<b.cap; 12 } 13 }; 14 edge p[20001]; 15 vector <edge> E[20001]; 16 int dist[20001]; 17 bool mex[20001],used[20001]; 18 int sg[20001]; 19 int n,m,k; 20 void addedge(int from,int to,int c){ 21 E[from].push_back((edge){to,c}); 22 } 23 void spfa(){ 24 memset(dist,-1,sizeof(dist)); 25 memset(used,0,sizeof(used)); 26 queue <int> q; 27 q.push(1); 28 dist[1]=0;used[1]=true; 29 while(q.size()>0){ 30 int now=q.front();q.pop(); 31 for(int i=0;i<E[now].size();i++){ 32 edge tmp=E[now][i]; 33 if(dist[tmp.to]==-1||dist[tmp.to]>dist[now]+tmp.cap) 34 { 35 dist[tmp.to]=dist[now]+tmp.cap; 36 if(!used[tmp.to]){ 37 q.push(tmp.to); 38 used[tmp.to]=true; 39 } 40 } 41 } 42 used[now]=false; 43 } 44 } 45 int main(){ 46 //freopen("b.in","r",stdin);freopen("b.out","w",stdout); 47 int x,y,c; 48 while(scanf("%d%d%d",&n,&m,&k)!=EOF) 49 { 50 for(int i=1;i<=n;i++)E[i].clear(); 51 for(int i=0;i<m;i++){ 52 scanf("%d%d%d",&x,&y,&c); 53 addedge(x,y,c); 54 addedge(y,x,c); 55 } 56 spfa(); 57 for(int i=1;i<=n;i++) 58 p[i]=((edge){i,dist[i]}); 59 sort(p+1,p+n+1); 60 int t=n; 61 while(t>0){ 62 bool f=false; 63 memset(mex,0,sizeof(mex)); 64 for(int i=0;i<E[p[t].to].size();i++){ 65 int tmp=E[p[t].to][i].to; 66 if(dist[tmp]>p[t].cap){mex[sg[tmp]]=true;f=true;} 67 } 68 for(int i=0;1;i++){ 69 if(mex[i]==false){sg[p[t].to]=i;break;} 70 } 71 if(f==false) sg[p[t].to]=1; 72 t--; 73 } 74 int ans=0; 75 for(int i=0;i<k;i++){ 76 scanf("%d",&x); 77 ans=ans^sg[x]; 78 } 79 printf(ans?"Alice\n":"Bob\n"); 80 } 81 82 //fclose(stdin);fclose(stdout); 83 return 0; 84 }
以上是关于SG函数-博弈论的主要内容,如果未能解决你的问题,请参考以下文章
ACM博弈论SG函数入门:博弈树SG函数的转移与子游戏的合并