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

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

是别人的代码:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值