Nyoj 取石子游戏(博弈专题)

23-取石子(一)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int t,n,m;

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        if(n%(m+1))printf("Win\n");
        else printf("Lose\n");
    }
    return 0;
}

135-取石子(二)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        int a,b,tag=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a,&b);
            tag^=a%(b+1);
        }
        if(tag)printf("Win\n");
        else printf("Lose\n");
    }
    return 0;
}

137-取石子(三)

161-取石子(四)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

int a,b;
double g=(1+sqrt(5))/2;

int main()
{
    while(~scanf("%d%d",&a,&b)){
        if(a>b)swap(a,b);
        int t=(b-a)*g;
        //用b-a与a/g判断相等的方法是错误的!
        if(a!=t)printf("1\n");
        else printf("0\n");
    }

    return 0;
}

358-取石子(五)

刚开始不知道是斐波那契博弈,就dfs打表打了一下,然后看错题了并且打出的是必胜点,改了改,打出了2,3,5,8,13,21,34这几个数,可以看出规律,n为斐波那契数时必败。

// 打表打出所有必败点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

bool dfs(int x,int k){
    if(x==0)return false;
    for(int i=1;i<=k;i++){
        if(i>x)break;
        if(!dfs(x-i,i*2))return true;
    }
    return false;
}

int main()
{
    for(int i=2;i<=100;i++){
        //第一次取枚举1~i-1
        bool f=false;
        for(int j=1;j<i;j++){
            if(dfs(i,j))f=true;
        }
        if(!f)printf("%d\n",i);
    }
    return 0;
}

// n很大,要定义为unsigned long long型
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long LL;

LL n;
LL f[110];

int main()
{
    f[0]=0;f[1]=1;
    for(int i=2;i<94;i++)
        f[i]=f[i-1]+f[i-2];
    while(cin>>n){  // 用cin/%llu读入n
        if(binary_search(f,f+94,n))printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}

585-取石子(六)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max_n=1e6+10;

int t,n;

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        int c,tag=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&c);
            tag^=c;
        }
        printf("%s\n",tag?"PIAOYI":"HRDV");
    }

    return 0;
}

833-取石子(七)

画画找规律,找到了一开始自己也不信,但是想一想,它是难度为1的博弈题!

#include<iostream> 
#include<cstdio>
#include<algorithm>
using namespace std;

int n;

int main()
{
	while(~scanf("%d",&n)){
		if(n==1||n==2)printf("Hrdv\n");
		else printf("Yougth\n");
	}
	return 0;
}

886-取石子(八)

Wythoff博弈,不算很难,但是注意点很多,WA了好多次,慢慢来~

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max_n=1e6+10;

int a,b;
int m[Max_n],n[Max_n];

double g=(1+sqrt(5))/2;

int main()
{
    int f;
    for(int i=0;i<=Max_n;i++){ //预处理出所有的奇异局势
        m[i]=i*g;
        n[i]=m[i]+i;
        if(m[i]>Max_n){
            f=i;break;
        }
    }
    while(~scanf("%d%d",&a,&b)&&a+b){
        if(a>b)swap(a,b);
        int t=(b-a)*g,k;
        //用b-a与a/g判断相等的方法是错误的!
        if(a!=t)printf("1\n");
        else {printf("0\n");continue;}
        
        if(a>t)   //两堆中同时取
            printf("%d %d\n",t,t+b-a);
            
        if(a==b){ //一堆中取
            k=lower_bound(n,n+f,a)-n;
            if(n[k]==a)printf("%d %d\n",m[k],a);
        }
        else {
            //大堆中取
            k=lower_bound(n,n+f,a)-n;
            if(n[k]==a)printf("%d %d\n",m[k],a);
            k=lower_bound(m,m+f,a)-m;
            if(m[k]==a&&b>n[k])printf("%d %d\n",a,n[k]);
            //小堆中取
            k=lower_bound(n,n+f,b)-n;
            if(n[k]==b&&a>m[k])printf("%d %d\n",m[k],b);
        }
    }

    return 0;
}
测试样例:
5 7
>1
>3 5 //两堆中取
>3 5 //大堆中取4个石子
>4 7 //小堆中取1个石子

5 6
>1
>1 2
>3 5

3 10
>1
>3 5

10 10
>1
>0 0
>6 10

888-取石子(九)

反尼姆博弈,真的不会,首先它不是ICG游戏,不可以用SG求解,然后自己P/N分析只能分析到两堆的情况,三堆以上就很复杂了。推荐一下知乎大佬王希的关于反尼姆博奕的回答。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int t,n;

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        int tag=0,ans=0,t;
        for(int i=1;i<=n;i++){
            scanf("%d",&t);
            if(t>1)ans++; //记录富裕堆的个数
            tag^=t;
        }
        if(!tag&&!ans||tag&&ans)printf("Yougth\n");
        else printf("Hrdv\n");
    }
    return 0;
}

913-取石子(十)

SG打表的运用,根据打表找规律,第2和第4种取法没有规律可寻!

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max_n=1e3+10;

int n;
int sg2[Max_n],sg4[Max_n],f[Max_n];
bool s[Max_n];

void get_SG(){ //第2和4种取法无规律,SG打表
    f[0]=1;f[1]=2;
    int N;
    for(int i=2;i<=1010;i++){
        f[i]=f[i-1]+f[i-2];
        if(f[i]>1010){N=i;break;}
    }
    sg2[0]=0;
    for(int i=1;i<=1010;i++){
        memset(s,0,sizeof(s));
        for(int j=0;i>=f[j]&&j<N;j++){
            s[sg2[i-f[j]]]=1;
        }
        for(int j=0;j<=i;j++){
            if(!s[j]){sg2[i]=j;break;}
        }
    }
    sg4[0]=0;
    for(int i=1;i<=1010;i++){
        memset(s,0,sizeof(s));
        s[sg4[i-1]]=1;
        for(int j=2;j<=i;j+=2){
            s[sg4[i-j]]=1;
        }
        for(int j=0;j<=i;j++){
            if(!s[j]){sg4[i]=j;break;}
        }
    }
}

int sg(int c,int i){ //得到第i种取法的sg值
    if(i==1)return c%3;
    else if(i==2)return sg2[c];
    else if(i==3)return c;
    else if(i==4)return sg4[c];
    else if(i==5)return c%2;
    else return c%(i+1);
}

int main()
{
    get_SG();
    while(~scanf("%d",&n)&&n){
        int tag=0,c;
        for(int i=1;i<=n;i++){
            scanf("%d",&c);
            tag^=sg(c,i);
        }
        printf("%s\n",tag?"Yougth":"Hrdv");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值