HDU1536,SG函数(①打表,②回溯),简单应用示例2

原创 2016年08月28日 16:36:14

0

1

将游戏拆分成多个子游戏,求各自的sg值再异或。

如何求sg函数值?如果查询次数过多,可以预先打表,然后查;如果查询次数相对不多,但是题目卡时间,可以回溯法,求哪个查哪个。

打表还有一个好处,把所有可能用到的sg值都求了出来,如果对时间有进一步要求的题目,可以打表以后寻找sg函数值的规律,直接根据规律用数学式子求sg值,以达到O(1)的sg查询速度。

回溯的好处是在于不需要找规律,且在线查询sg值,查询时间略快于打表,因为它总是从要查找的sg值开始,然后往前回溯,如果遇到已知sg值就可以返回,并保存所有算过的sg值。比起打表,要查找的sg值可能远远小于最后一个数,这样就不用打表一直求到最后一个数。

 

2

①打表sg函数值(320ms):

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
//#define Local_judge
//HDU1536,SG函数,简单应用示例2
using namespace std;
int k,m,l;
int number;
int fib[110];
int sg[10010];
bool bj[10010];
int res;
void Get_sg(int t,int x){//x是sg数组上限,t是有多少种取石子的方法
    memset(sg,0,sizeof(sg));
    for(int i=1;i<=x;i++){
        memset(bj,0,sizeof(bj));
        for(int j=1;j<=t&&fib[j]<=i;j++){
            bj[sg[i-fib[j]]]=1;
        }
        for(int j=0;j<=x;j++){
            if(!bj[j]){
                sg[i]=j;
                break;
            }
        }
    }
}
int main(){
   
    #ifdef ONLINE_JUDGE//HDU上已经定义的宏
    #else
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif // Judge
    
    /*
    #ifdef Local_judge //类似的,可以自己定义,提交时注释掉最上面的define Local_judge
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif // ACM
    */
    while(~scanf("%d",&k)&&k){
        for(int i=1;i<=k;i++){
            scanf("%d",&fib[i]);
        }
        sort(fib+1,fib+1+k);
        scanf("%d",&m);
        Get_sg(k,10000);</p><p>        //for(int i=0;i<=100;i++) cout<<sg[i]<<endl;</p><p>        for(int i=1;i<=m;i++){
            scanf("%d",&l);
            scanf("%d",&number);
            res=sg[number];
            for(int j=2;j<=l;j++){
                scanf("%d",&number);
                res^=sg[number];
            }
            if(res==0){
                cout<<"L";
            }
            else{
                cout<<"W";
            }
        }
        cout<<endl;
    }
}

 


 ②回溯在线求sg函数值(280ms):

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
///注意一个缺陷:Sg_huisu中每次都要bool visted[n];memset();如果最大sg函数值n大一些,估计这个方法就爆栈了。所以理解这种回溯在线查找sg值的思想即可。
using namespace std;
int k,m,num,number;
int s[110];
int sg[10010];//sg上限是石子个数而不是石子堆堆数
int Sg_huisu(int x){//很多人把这一步叫做dfs,但是我认为称为回溯更恰当一些。因为dfs找到合适的就return了, 而这里每一层都要返回一个结点出发到达的每一个节点的情况,然后进行比较,再返回上一层。
    if(sg[x]!=-1)
        return sg[x];
    bool visted[110];//visted[x],x上限是最大的sg函数值,你如果看不出来,可以打表所有sg值看看....
    memset(visted,0,sizeof(visted));
    for(int i=0;i<k;i++){
        if(s[i]<=x){
            Sg_huisu(x-s[i]);
            visted[sg[x-s[i]]]=1;
        }
    }
    for(int i=0;;i++){//同上一个注释,建立在visted数组内元素个数不超过最大sg值的基础上
        if(!visted[i]){
            sg[x]=i;
            break;
        }
    }
    return sg[x];
}
int main()
{
    while(~scanf("%d",&k)&&k){
        for(int i=0;i<k;i++){
            scanf("%d",&s[i]);
        }
        scanf("%d",&m);
        sort(s,s+k);
        memset(sg,-1,sizeof(sg));//针对分解后的子游戏,所以下文中几次询问或者每次询问时给出几个子游戏,对sg[]并没有影响。
        while(m--){
            scanf("%d",&num);
            int ans=0;//0^0=0,0^1=1;
            for(int j=0;j<num;j++){
                scanf("%d",&number);
                ans^=Sg_huisu(number);
            }
            if(ans==0){
                cout<<"L";
            }
            else{
                cout<<"W";
            }
        }
        cout<<endl;
    }
}


 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

HDU1536 SG函数的简单应用

S-Nim Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm...

hdu 1536 &&hdu1944 S-Nim (sg函数打表)

S-NimTime Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Subm...

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

sg函数:sg函数是博弈中的确定一个position性质的一个函数,全称是sprague-grundy。 性质1:对于所有的p-position,都有sg = 0;对于所有的n-position...

HDU 1536 S-Nim (SG函数)

S-Nim Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su...
  • d_x_d
  • d_x_d
  • 2016年07月20日 16:33
  • 1178

HDU 1536 S-Nim [SG函数]【博弈】

题目连接 :http://acm.hdu.edu.cn/showproblem.php?pid=1536——————————————.S-NimTime Limit: 5000/1000 MS (Ja...

hdu 1536 S-Nim|| poj 2960 S-Nim (sg函数)

#include #include int s[110]; int sg[10010],hash[110]; int n, m; int getsg(int x) //sg模板 { ...

HDU_1536 博弈论-sg函数

//博弈论之SG函数(第一道SG) //题意 :输入比较麻烦,有n堆石头每次只能取S集合中的数字颗数,取完最后一颗为胜,问先手胜负; //输入:S集合中有t个数;对于这个测试用例有l个询问行,接下来每...

S-Nim(hdu1536+SG函数)

S-Nim Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su...

HDOJ 1536 SG函数的基本应用

从题意来看,是基本的SG函数应用,把刚学的set用进去优化,发现不行... TLE... 再看看SG的原理,网上大部分都是采用递归,而那些题解报告都是一把抄,嗤之以鼻.. 下面是直接TLE的代码...

ACM-SG函数之S-Nim——hdu1536 hdu1944 poj2960

ACM SG函数 博弈 S-Nim hdu1536 hdu1944 poj2960
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU1536,SG函数(①打表,②回溯),简单应用示例2
举报原因:
原因补充:

(最多只允许输入30个字)