博弈——sg函数的原理和优化

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  

/* 

  1. 收获: 
  2. */  
  3. #include<iostream>   
  4. #include<cstdlib>   
  5. #include<vector>   
  6. #include<map>   
  7. #include<cstring>   
  8. #include<set>   
  9. #include<string>   
  10. #include<algorithm>   
  11. #include<sstream>   
  12. #include<ctype.h>   
  13. #include<fstream>   
  14. #include<string.h>   
  15. #include<stdio.h>   
  16. #include<math.h>   
  17. #include<stack>   
  18. #include<queue>   
  19. #include<ctime>   
  20. //#include<conio.h>   
  21. using namespace std;  
  22.   
  23. const int INF_MAX=0x7FFFFFFF;  
  24. const int INF_MIN=-(1<<31);  
  25.   
  26. const double eps=1e-10;  
  27. const double pi=acos(-1.0);  
  28.   
  29. #define pb push_back   //a.pb( )   
  30. #define chmin(a,b) ((a)<(b)?(a):(b))   
  31. #define chmax(a,b) ((a)>(b)?(a):(b))   
  32.   
  33.   
  34. template<class T> inline T gcd(T a,T b)//NOTES:gcd(   
  35.   {if(a<0)return gcd(-a,b);if(b<0)return gcd(a,-b);return (b==0)?a:gcd(b,a%b);}  
  36. template<class T> inline T lcm(T a,T b)//NOTES:lcm(   
  37.   {if(a<0)return lcm(-a,b);if(b<0)return lcm(a,-b);return a*(b/gcd(a,b));}  
  38.   
  39.   
  40. typedef pair<intint> PII;  
  41. typedef vector<PII> VPII;  
  42. typedef vector<int> VI;  
  43. typedef vector<VI> VVI;  
  44. typedef long long LL;  
  45. int dir_4[4][2]={{0,1},{-1,0},{0,-1},{1,0}};  
  46. int dir_8[8][2]={{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};  
  47. //下,左下,左,左上,上,右上,右,右下。   
  48.   
  49. //******* WATER ****************************************************************   
  50.   
  51.   
  52. const int MAXN = 10500;  
  53. bool judge[150];  
  54. int sg[MAXN];  
  55. int M[150];  
  56. const int Init = 1e7;  
  57. int Num;  
  58.   
  59. void input_m()  
  60. {  
  61.     for(int i = 0; i < Num; i++)  
  62.     {  
  63.         cin>>M[i];  
  64.     }  
  65.     return ;  
  66. }  
  67.   
  68. void debug()  
  69. {  
  70.     cout<<"sg function"<<endl;  
  71.     for(int i = 0; i < 100; i++)  
  72.     {  
  73.         cout<<i<<" "<<sg[i]<<endl;  
  74.     }  
  75.     return ;  
  76. }  
  77.   
  78. void getsg()  
  79. {  
  80.     for(int i = 0; i < MAXN; i++)  
  81.     {  
  82.         memset(judge, falsesizeof(judge));  
  83.         //int tsg = Init;   
  84.         for(int j = 0; j < Num; j++)  
  85.         {  
  86.             int ps = i - M[j];  
  87.             if(ps >= 0) judge[sg[ps]] = true;  
  88.         }  
  89.         //if(tsg == Init) tsg = 0;   
  90.         for(int j = 0; j < Num + 1; j++)  
  91.         {  
  92.             if(judge[j] == false)  
  93.             {  
  94.                 sg[i] = j;  
  95.                 break;  
  96.             }  
  97.         }  
  98.     }  
  99.     //debug();   
  100.     return ;  
  101. }  
  102. int main()  
  103. {  
  104.     //freopen("input.txt","r",stdin);   
  105.     //freopen("output.txt","w",stdout);   
  106.     while(cin>>Num, Num)  
  107.     {  
  108.         input_m();  
  109.         getsg();  
  110.         int num;  
  111.         cin>>num;  
  112.         while(num--)  
  113.         {  
  114.             int nn, tp;  
  115.             cin>>nn;  
  116.             int ret = 0;  
  117.             for(int i = 0; i < nn; i++)  
  118.             {  
  119.                 cin>>tp;  
  120.                 ret ^= sg[tp];  
  121.             }  
  122.             if(ret == 0) cout<<"L";  
  123.             else cout<<"W";  
  124.         }  
  125.         cout<<endl;  
  126.     }  
  127.     return 0;  
  128.     //printf("%.6f\n",(double)clock()/CLOCKS_PER_SEC);   
  129. }  
/*
收获:
*/
#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);
}

 

 

方法二:递归迭代

以下

  1. #include"iostream"   
  2. #include"algorithm"   
  3. #include"string.h"   
  4. using namespace std;  
  5. int s[101],sg[10001],k;  
  6. int getsg(int m)  
  7. {  
  8.     int hash[101]={0};  
  9.     int i;  
  10.     for(i=0;i<k;i++){  
  11.         if(m-s[i]<0)  
  12.             break;  
  13.         if(sg[m-s[i]]==-1)  
  14.             sg[m-s[i]]=getsg(m-s[i]);  
  15.         hash[sg[m-s[i]]]=1;  
  16.     }  
  17.     for(i=0;;i++)  
  18.         if(hash[i]==0)  
  19.             return i;  
  20.    
  21.    
  22. }  
  23. int main()  
  24. {  
  25.     //int k;   
  26.    // freopen("game.in","r",stdin);   
  27.     //freopen("game.out","w",stdout);   
  28.     while(cin>>k,k)  
  29.     {  
  30.         int i;  
  31.         for(i=0;i<k;i++)  
  32.             cin>>s[i];  
  33.         sort(s,s+k);  
  34.         memset(sg,-1,sizeof(sg));  
  35.         sg[0]=0;  
  36.         int t;  
  37.         cin>>t;      
  38.         while(t--)  
  39.         {  
  40.                
  41.             int n,m;  
  42.             cin>>n;  
  43.             int ans=0;  
  44.             while(n--)  
  45.             {  
  46.                 cin>>m;  
  47.                 if(sg[m]==-1)  
  48.                     sg[m]=getsg(m);  
  49.                 ans^=sg[m];  
  50.             }  
  51.             if(ans)  
  52.                 cout<<'W';  
  53.             else cout<<'L';  
  54.         }  
  55.         cout<<endl;  
  56.     }  
  57.     return 0;  
  58. }  
posted @ 2013-08-19 19:38  我家小破孩儿  阅读(1048)  评论(0编辑  收藏  举报