ACM——博弈論 (以SG的求法為主)

來源:互聯網
上載者:User

HDU 1847Good Luck in CET-4 Everybody!

n個石子取2的次冪個,0為terminal position

P/N分析和求SG值方法都可以,找規律的話模3餘0也能過

主要是為了練習SG的求法

#include <cstdio>#include <cstring>//單純博弈型 也可用P/N分析法int x[12],SG[1050];bool vis[1050];void init(){    for (int i=0 ; i<11 ; ++i)        x[i]=1<<i;    SG[0]=0;    for (int i=1 ; i<1002 ; ++i)//get Sprague-Grundy value;    {        memset (vis , 0 , sizeof(vis));        for (int j=0 ; x[j]<=i ; ++j)        {            vis[SG[i-x[j]]]=true;        }        for (int j=0 ; ; ++j)        {            if(!vis[j]){SG[i]=j;break;}        }    }    for (int i=0 ; i<100 ; ++i)    printf("num=%d sg=%d\n",i,SG[i]);}int main (){    int n;    init();    while (~scanf("%d",&n))    {        if(SG[n])puts("Kiki");        else puts("Cici");    }    return 0;}

 

HDU 3980 Paint Chain

n元環,每次取連續的m個元素,最先不能取者敗。

可以考慮n<m和n>=m兩種情況,第一種情況結果顯然,第二種將取過1次後剩下的n-m元鏈進行求SG值,前m-1個狀態的SG值明顯為0,m為1,之後的狀態取走m元素之後,會將剩下的2段分成2份(考慮0的情況),分別求其SG值,從而得到當前的狀態的一個後繼SG值。

 

 

#include <cstdio>#include <cstring>const int maxn=1005;int SG[maxn];bool vis[maxn];bool sg(int n , int m)//get SG value{    memset(SG , 0 , sizeof(SG));    SG[m]=1;    for (int i=m+1 ; i<=n ; ++i)    {        memset (vis , 0 , sizeof(vis));        for (int j=0 ; j<i-m ; ++j)        {            vis[SG[j]^SG[i-m-j]]=true;        }        for (int j=0 ; ; ++j)        {            if(!vis[j]){SG[i]=j;break;}        }    }    //for (int i=0 ; i<=n ; ++i)        //printf("%d %d \n",i,SG[i]);    return SG[n];}int main (){    int cas;    int n,m;    scanf("%d",&cas);    for (int I=1 ; I<=cas ; ++I)    {        scanf("%d%d",&n,&m);        if(m>n)printf("Case #%d: abcdxyzk\n",I);        else if(sg(n-m,m))printf("Case #%d: abcdxyzk\n",I);        else printf("Case #%d: aekdycoin\n",I);    }    return 0;}

POJ 3537 Crosses and Crosses

 

 

給一個1*n的長方形格子,在格子裡輪流畫X,最先得到3個連續X的人即為winner

#include <cstdio>#include <cstring>const int maxn=2005;int SG[maxn];bool vis[maxn];void sg(){    memset (SG , 0 , sizeof(SG));    SG[1]=1;SG[2]=1;SG[3]=1;//SG[4]=1;    for (int i=4; i<maxn ; ++i)    {        memset (vis , 0 , sizeof(vis));        for (int j=2 ; j<i ; ++j)        {            if((i-j-1<2))vis[SG[j-2]^0]=true;            else vis[SG[j-2]^SG[i-j-1-2]]=true;        }        for (int j=0 ;  ; ++j)            if(!vis[j]){SG[i]=j ; break;}    }    //for (int i=0; i<50 ; ++i)    //printf("SG%d=%d\n",i,SG[i]);}int main (){    sg();    int n;    while (~scanf("%d",&n))    {        if(SG[n])puts("1");        else puts("2");    }    return 0;}

 

 

POJ 2425 A Chess Game在DAG上搜尋的NIM遊戲,其實和在多堆石子裡拿東西是一樣的,要熟練各種遊戲模型之間的轉化,找出更新SG的方法就可以了一開始清空vis和visit的時候 把visit的大小寫成了sizeof(vis) DT了一天才發現Bug >< 
#include <cstdio>#include <cstring>const int maxm=2005000;const int maxn=1005;struct Edge {    int v,next;}edge[maxm];int head[maxn],cnt;void addedge(int u,int v){    edge[cnt].v=v;    edge[cnt].next=head[u];    head[u]=cnt++;}bool vis[maxn],visit[maxn][maxn];//for dfs   for sg;int SG[maxn];void dfs (int u){    if(~SG[u]) return ;    //vis[u]=true;    int p=head[u];    for ( ; ~p ; p=edge[p].next)    {        int v=edge[p].v;        //printf("%d ",u);        //if(vis[v])continue;        dfs(v);        visit[u][SG[v]]=true;    }    for (int i=0 ; true ; ++i)    {        if(!visit[u][i]){SG[u]=i;break;}    }}int main (){    int n,node,v,m,t;    while (~scanf("%d",&n))    {        memset (head , -1 , sizeof(head));        memset (SG , -1 , sizeof(SG));        cnt=0;        for (int u=0 ; u<n ; ++u)        {            scanf("%d",&node);            if(!node)SG[u]=0;            for (int i=0 ; i<node ; ++i)            {                scanf("%d",&v);                addedge(u , v);            }        }        memset (vis , false , sizeof(vis));        memset (visit , false , sizeof(visit));        for(int i=0 ; i<n ; ++i)        {            if(vis[i])continue;            dfs(i);        }        /*for (int i=0 ; i<n ; ++i)        {            printf("%d\t",SG[i]);        }*/        while (scanf("%d",&m),m)        {            int nim=0;            for(int i=0 ; i<m ; ++i)            {                scanf("%d",&t);                nim^=SG[t];            }            puts(nim?"WIN":"LOSE");        }    }    return 0;}
POJ 1704 Georgia and Bob(階梯博弈(目標的NP態只和奇數階的NP態有關)) 知道如何轉換的話就很簡單,關鍵是我不知道,推了半天,蒙了各種感覺有道理的轉化方法都WA了,最後還是看了題解,還是很好理解的。我的理解:對於棋盤上棋子,我們兩兩對其綁定,如果是奇數個,我們可以看做是和0處的一個棋子綁定,通過找規律我們可以發現,每對棋子的前一個棋子移動之後,後一個棋子可以移動和前一個棋子相同的步數是不影響結果的,即這是一個相對於比賽結果的平衡態,所以我們可以把所有的棋子對都平移到左邊並保持棋子對之間的距離不變,這時我們發現我們要做得只是讓每對棋子的後者和前者距離變為1,以及向前平移每對棋子,這兩種操作後者是不影響結果的,於是我們將前者的操作轉化成相應數值的NIM型博弈,剩下的大家就都能知道了
#include <cstdio>#include <algorithm>using namespace std;const int maxn=1005;int nim[maxn];int n;int main (){    int cas;    scanf("%d",&cas);    while (cas--)    {        scanf("%d",&n);        int ans=0;        nim[0]=0;        for (int i=1 ; i<=n ; ++i)        {            scanf("%d",nim+i);        }        sort(nim,nim+n+1);        for (int i=0 ; i<(n+1)/2 ; ++i)        {            ans^=(nim[n-2*i]-nim[n-2*i-1]-1);            //printf("%d  %d  %d\n",nim[n-2*i],nim[n-2*i-1],ans);        }        puts(ans?"Georgia will win":"Bob will win");    }    return 0;}

 JOJ 2520  A special queen  

#include <cstdio>#include <cstring>int SG[105][105];bool vis[5000];/*棋盤上的2維SG遞推,非組合遊戲可以不用SG*//*輸出格式很噁心*/int main (){    int l,w;    SG[0][0]=0;    for (int i=1 ; i<105 ; ++i)    {        SG[i][0]=i;        for (int j=1 ; j<105 ; ++j)        {            SG[0][j]=j;            if(i==j){SG[i][i]=i+1;continue;}            memset (vis , 0 , sizeof(vis));            for (int k=0 ; k<j ; ++k)                vis[SG[i][k]]=true;            for (int k=0 ; k<i ; ++k)                vis[SG[k][j]]=true;            for (int k=1 ; k<=i&&k<=j ; ++k)                vis[SG[i-k][j-k]]=true;            for (int k=0 ;  ; ++k)            if(!vis[k]){SG[i][j]=k ; break;}        }    }/*    for (int i=0 ; i<25 ; ++i)    {        for (int j=0 ; j<25 ; ++j)            printf("%d ",SG[i][j]);        puts("");    }*/    while (~scanf("%d*%d",&l,&w))    {        if(l==1 || w==1){printf("G will win\n");continue;}        bool flag=false;        bool first=false;        for (int i=0 ; i<l ; ++i)        {            if(!SG[i][w-1])            {                flag=true;                if(first)printf(" ");                printf("(%d,%d)",i,w-1);                first=true;            }        }        for (int i=0 ; i<w-1 ; ++i)        {            if(!SG[l-1][i])            {                flag=true;                if(first)printf(" ");                printf("(%d,%d)",l-1,i);                first=true;            }        }        if(!flag)printf("G will win");        printf("\n");    }    return 0;}

  ZOJ Monthly, September 2011
A Game Between Alice and Bob 博弈論nim的變形,合數分解,被常數給坑了

#include <cstdio>#include <cstring>#include <cmath>#define abs(a) (a)>(0)?(a):(-(a))#define  min(a,b) (a>b?b:a)const int maxn=100000+123;typedef int  typen;typen a[maxn];typen count[maxn];const int maxp = 5000;int prime[maxp + 1];//prime[0] is the counterint getPrime(){    memset (prime, 0, sizeof (prime));    for (int i = 2 ; i <= maxp ; i++)    {        if (!prime[i]) prime[++prime[0]] = i;        for (int j = 1; j <= prime[0] && prime[j] * i <= maxp ; j++)        {            prime[prime[j]*i] = 1;            if (i % prime[j] == 0) break;        }    }    return prime[0];}int getFactors(typen x){    int facCnt = 0;    typen tmp = x;    for(int i = 1; prime[i]*prime[i] <= tmp ; ++i)    {        if(tmp % prime[i] == 0)        {            while(tmp % prime[i] == 0)            tmp /= prime[i],++facCnt;        }    }    if(tmp != 1)        ++facCnt;    return facCnt;}int cas=0;int main (){    int n;    getPrime();    while ( ~scanf("%d",&n) )    {        memset (count , 0 , sizeof(count));        int sum=0;        for (int i=0 ; i<n ; ++i)        {            scanf("%d",a+i);            count[i]=getFactors(a[i]);        }        for (int i=0 ; i<n ; ++i)        {            sum^=count[i];        }        if(sum)        {            int i;            for (i=0 ; i<n ; ++i)//從            {                if((sum^count[i])<count[i])break;            }            printf("Test #%d: Alice %d\n",++cas,i+1);        }        else printf("Test #%d: Bob\n",++cas);    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.