您的位置:首页 > 其它

博弈-sg函数的原理和优化(hdu-1536)

2013-07-22 15:57 267 查看
sg函数:sg函数是博弈中的确定一个position性质的一个函数,全称是sprague-grundy。

性质1:对于所有的p-position,都有sg = 0;对于所有的n-position都有sg != 0;

性质2:某点a的sg函数的值由它的后继的sg函数的值来决定,设后继为b, c, d, e……则sg(a) = mex(sg(a), sg(b), sg(c), sg(d), sg(e),……)

mex是不属于这个集合的最小非负整数。

应用范围:在此无环图中谁无法再次移动,便是输。(如果谁无法移动,便是赢,暂时不知如何解决。)

应用:通过判断该点,sg = 0是p点,sg != 0是N点。

构造sg函数的方法:

方法一:打表

例题:hdu-1536-S-nim 点击打开链接

[cpp]
view plaincopyprint?

/* 
收获: 
*/  
#include<iostream>   
#include<cstdlib>
  
#include<vector>   
#include<map>   
#include<cstring>   
#include<set>   
#include<string>   
#include<algorithm>
  
#include<sstream>   
#include<ctype.h>
  
#include<fstream>   
#include<string.h>
  
#include<stdio.h>   
#include<math.h>   
#include<stack>   
#include<queue>   
#include<ctime>   
//#include<conio.h>   
using namespace std;  
  
const int INF_MAX=0x7FFFFFFF;  
const int INF_MIN=-(1<<31);  
  
const double eps=1e-10;  
const double pi=acos(-1.0);  
  
#define pb push_back   //a.pb( )
  
#define chmin(a,b) ((a)<(b)?(a):(b))
  
#define chmax(a,b) ((a)>(b)?(a):(b))
  
  
  
template<class T> inline T gcd(T a,T b)//NOTES:gcd(
  
  {if(a<0)return gcd(-a,b);if(b<0)return gcd(a,-b);return (b==0)?a:gcd(b,a%b);}  
template<class T> inline T lcm(T a,T b)//NOTES:lcm(
  
  {if(a<0)return lcm(-a,b);if(b<0)return lcm(a,-b);return a*(b/gcd(a,b));}  
  
  
typedef pair<int, int> PII;  
typedef vector<PII> VPII;  
typedef vector<int> VI;  
typedef vector<VI> VVI;  
typedef long long LL;  
int dir_4[4][2]={{0,1},{-1,0},{0,-1},{1,0}};  
int dir_8[8][2]={{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};  
//下,左下,左,左上,上,右上,右,右下。   
  
//******* WATER ****************************************************************
  
  
  
const int MAXN = 10500;  
bool judge[150];  
int sg[MAXN];  
int M[150];  
const int Init = 1e7;  
int Num;  
  
void input_m()  
{  
    for(int i = 0; i < Num; i++)  
    {  
        cin>>M[i];  
    }  
    return ;  
}  
  
void debug()  
{  
    cout<<"sg function"<<endl;  
    for(int i = 0; i < 100; i++)  
    {  
        cout<<i<<" "<<sg[i]<<endl;  
    }  
    return ;  
}  
  
void getsg()  
{  
    for(int i = 0; i < MAXN; i++)  
    {  
        memset(judge, false, sizeof(judge));  
        //int tsg = Init;   
        for(int j = 0; j < Num; j++)  
        {  
            int ps = i - M[j];  
            if(ps >= 0) judge[sg[ps]] = true;  
        }  
        //if(tsg == Init) tsg = 0;
  
        for(int j = 0; j < Num + 1; j++)  
        {  
            if(judge[j] == false)  
            {  
                sg[i] = j;  
                break;  
            }  
        }  
    }  
    //debug();   
    return ;  
}  
int main()  
{  
    //freopen("input.txt","r",stdin);
  
    //freopen("output.txt","w",stdout);
  
    while(cin>>Num, Num)  
    {  
        input_m();  
        getsg();  
        int num;  
        cin>>num;  
        while(num--)  
        {  
            int nn, tp;  
            cin>>nn;  
            int ret = 0;  
            for(int i = 0; i < nn; i++)  
            {  
                cin>>tp;  
                ret ^= sg[tp];  
            }  
            if(ret == 0) cout<<"L";  
            else cout<<"W";  
        }  
        cout<<endl;  
    }  
    return 0;  
    //printf("%.6f\n",(double)clock()/CLOCKS_PER_SEC);
  
}  

/*
收获:
*/
#include<iostream>
#include<cstdlib>
#include<vector>
#include<map>
#include<cstring>
#include<set>
#include<string>
#include<algorithm>
#include<sstream>
#include<ctype.h>
#include<fstream>
#include<string.h>
#include<stdio.h>
#include<math.h>
#include<stack>
#include<queue>
#include<ctime>
//#include<conio.h>
using namespace std;

const int INF_MAX=0x7FFFFFFF;
const int INF_MIN=-(1<<31);

const double eps=1e-10;
const double pi=acos(-1.0);

#define pb push_back   //a.pb( )
#define chmin(a,b) ((a)<(b)?(a):(b))
#define chmax(a,b) ((a)>(b)?(a):(b))

template<class T> inline T gcd(T a,T b)//NOTES:gcd(
{if(a<0)return gcd(-a,b);if(b<0)return gcd(a,-b);return (b==0)?a:gcd(b,a%b);}
template<class T> inline T lcm(T a,T b)//NOTES:lcm(
{if(a<0)return lcm(-a,b);if(b<0)return lcm(a,-b);return a*(b/gcd(a,b));}

typedef pair<int, int> PII;
typedef vector<PII> VPII;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef long long LL;
int dir_4[4][2]={{0,1},{-1,0},{0,-1},{1,0}};
int dir_8[8][2]={{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
//下,左下,左,左上,上,右上,右,右下。

//******* WATER ****************************************************************

const int MAXN = 10500;
bool judge[150];
int sg[MAXN];
int M[150];
const int Init = 1e7;
int Num;

void input_m()
{
for(int i = 0; i < Num; i++)
{
cin>>M[i];
}
return ;
}

void debug()
{
cout<<"sg function"<<endl;
for(int i = 0; i < 100; i++)
{
cout<<i<<" "<<sg[i]<<endl;
}
return ;
}

void getsg()
{
for(int i = 0; i < MAXN; i++)
{
memset(judge, false, sizeof(judge));
//int tsg = Init;
for(int j = 0; j < Num; j++)
{
int ps = i - M[j];
if(ps >= 0) judge[sg[ps]] = true;
}
//if(tsg == Init) tsg = 0;
for(int j = 0; j < Num + 1; j++)
{
if(judge[j] == false)
{
sg[i] = j;
break;
}
}
}
//debug();
return ;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
while(cin>>Num, Num)
{
input_m();
getsg();
int num;
cin>>num;
while(num--)
{
int nn, tp;
cin>>nn;
int ret = 0;
for(int i = 0; i < nn; i++)
{
cin>>tp;
ret ^= sg[tp];
}
if(ret == 0) cout<<"L";
else cout<<"W";
}
cout<<endl;
}
return 0;
//printf("%.6f\n",(double)clock()/CLOCKS_PER_SEC);
}


方法二:递归迭代

以下

[cpp]
view plaincopyprint?

#include"iostream"   
#include"algorithm"   
#include"string.h"
  
using namespace std;  
int s[101],sg[10001],k;  
int getsg(int m)  
{  
    int hash[101]={0};  
    int i;  
    for(i=0;i<k;i++){  
        if(m-s[i]<0)  
            break;  
        if(sg[m-s[i]]==-1)  
            sg[m-s[i]]=getsg(m-s[i]);  
        hash[sg[m-s[i]]]=1;  
    }  
    for(i=0;;i++)  
        if(hash[i]==0)  
            return i;  
   
   
}  
int main()  
{  
    //int k;   
   // freopen("game.in","r",stdin);
  
    //freopen("game.out","w",stdout);
  
    while(cin>>k,k)  
    {  
        int i;  
        for(i=0;i<k;i++)  
            cin>>s[i];  
        sort(s,s+k);  
        memset(sg,-1,sizeof(sg));  
        sg[0]=0;  
        int t;  
        cin>>t;      
        while(t--)  
        {  
               
            int n,m;  
            cin>>n;  
            int ans=0;  
            while(n--)  
            {  
                cin>>m;  
                if(sg[m]==-1)  
                    sg[m]=getsg(m);  
                ans^=sg[m];  
            }  
            if(ans)  
                cout<<'W';  
            else cout<<'L';  
        }  
        cout<<endl;  
    }  
    return 0;  
}  

#include"iostream"
#include"algorithm"
#include"string.h"
using namespace std;
int s[101],sg[10001],k;
int getsg(int m)
{
int hash[101]={0};
int i;
for(i=0;i<k;i++){
if(m-s[i]<0)
break;
if(sg[m-s[i]]==-1)
sg[m-s[i]]=getsg(m-s[i]);
hash[sg[m-s[i]]]=1;
}
for(i=0;;i++)
if(hash[i]==0)
return i;

}
int main()
{
//int k;
// freopen("game.in","r",stdin);
//freopen("game.out","w",stdout);
while(cin>>k,k)
{
int i;
for(i=0;i<k;i++)
cin>>s[i];
sort(s,s+k);
memset(sg,-1,sizeof(sg));
sg[0]=0;
int t;
cin>>t;
while(t--)
{

int n,m;
cin>>n;
int ans=0;
while(n--)
{
cin>>m;
if(sg[m]==-1)
sg[m]=getsg(m);
ans^=sg[m];
}
if(ans)
cout<<'W';
else cout<<'L';
}
cout<<endl;
}
return 0;
}


是别人的代码:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: