博弈-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);
}
方法二:递归迭代
以下
[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;
}
是别人的代码:
性质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; }
是别人的代码:
相关文章推荐
- 博弈-sg函数的原理和优化(hdu-1536)
- hdu1536 & 1944 S-NIM 博弈 SG函数
- hdu 1536、hdu 1944 S-Nim(博弈SG函数)
- HDU 1536 && HDU 1944 S-Nim (Nim博弈、SG函数模板)
- [ACM] hdu 1536 S-Nim(Nim组合博弈 SG函数打表)
- [ACM] hdu 1536 S-Nim(Nim组合博弈 SG函数打表)
- [ACM] hdu 1536 S-Nim(Nim组合博弈 SG函数打表)
- HDU 1536 S-Nim (博弈 sg函数 Nim和)
- 博弈 hdu 1536 SG函数解法
- HDU 1536 S-Nim 博弈,SG函数
- 博弈——sg函数的原理和优化
- HDU 1536 S-Nim [SG函数]【博弈】
- HDU-4678 Mine(BFS,NIM博弈,SG函数)
- hdu——3032(博弈之寻找sg函数)
- [ACM] hdu 1848 Fibonacci again and again(Nim博弈 SG函数)
- hdu 1848 博弈之SG函数的使用
- hdu 1536 S-Nim(SG函数)
- HDU-4678 Mine 博弈SG函数
- hdu 1079 Calendar Game (SG函数)(博弈——找规律)
- hdu 1847 博弈基础题 SG函数 或者规律2种方法