博弈论(Game Theory)解题报告

 P4018 Roy&October之取石子

#规律 #数学

数字有这几种情况

一、2、3、5都是质数;

二、6是第一个两个质数的幂之和。

三、6的倍数 6*n,一定不是单个质数的幂次方。因为除2外的质数都是奇数,奇数的乘积是奇数。对于2,因为6*n包含因子3,所以 6*n不是2的幂

四、对于所有6的倍数。先手无法取到6,每次都由后手补到6。如此循环直至取完,后手必胜。

五、对于所有非6的倍数,先手可以取1-5个将其化为6的倍数,转为四。

所以6的倍数,先手必败 。

石子游戏

#必胜态和必败态

G-石子游戏_第四届上海理工大学程序设计全国挑战赛 (nowcoder.com)

刚开始暴力打表,没发现规律

int dfs(int k,int l)
{
	if(k>=l) return 0; //必败态
	for(int i=1;i<=k;i++)
	{
		if(k+i<=l&&dfs(k+i,l)==0)
			return 1;           //下一个人的状态是必败态
	}
	return 0;
}

 打完后一周,朋友提供了思路,恍然大悟

倒 推

终态:now>=k

必胜态:ceil(k/2)<now<k

必败态:now=ceil(k/2)-1

所以每次先手添加石子,把状态推到必败态,就能赢

递归每一次的必败态,看先手能否把状态推到必败态送给后手

void solve()
{
	double n,k;
	cin>>n>>k;
	if(n==k) {cout<<"Bob"<<endl;return;} 
	while(n<k)
	{
		if(n>=ceil(k/2)) //先手的初始状态能达到第一次的必败态
		{
			cout<<"Alice"<<endl;
			return;
		}
		else k=ceil(k/2)-1; //继续递归寻找第一次的必败态
	}
	cout<<"Bob"<<endl; //先手的初始状态不能达到第一次的必败态
	return;
}

 Alice and Bob


A-Alice and Bob_2024牛客五一集训派对day4 (nowcoder.com)

这题是队友做的,赛后队友讲了一下思路

打 表

首先把一次能取完的情况标记,接着对必败态上的必胜态进行标记

int main(){
    for(int i=0;i<=5000;i++)
    for(int j=0;j<=5000;j++){
            if(!win[i][j]){
                for(int k=1;i+k<=5000;k++)
                for(int s=0;j+k*s<=5000;s++)
                win[i+k][j+k*s]=1;
                for(int k=1;j+k<=5000;k++)
                for(int s=0;i+k*s<=5000;s++)
                win[i+s*k][j+k]=1;
        }
    }
    cin>>t;
    while(t--){
        cin>>n>>m;
        if(win[n][m]) cout<<"Alice"<<endl;
        else cout<<"Bob"<<endl;
    }
    return 0;
}

 P3150 pb的游戏(1)

P3150 pb的游戏(1) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

偶数则先手必胜

如果是奇数,只能分割为奇数和偶数。无论先手如何拆解,后手如果能得到奇数,就将奇数分解为偶数+1,把作为必败态的偶数给先手。

欧几里得的游戏

P1290 欧几里德的游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

bool sg(int x,int y)
{
    if(!y) return 1;
    if(x/y==1)
    {
        return !sg(y,x%y);
    }
    return 1;
}

void solve()
{
    int a,b,c,d;
    cin>>a>>b;
    c=max(a,b);
    d=min(a,b);
    a=c,b=d;
    if(sg(a,b)) cout<<"Stan wins"<<endl;
    else cout<<"Ollie wins"<<endl;
}

P2953 [USACO09OPEN] Cow Digit Game S

P2953 [USACO09OPEN] Cow Digit Game S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

清楚概念 

必胜态:后继状态存在必败态

必败态:后继状态全为必胜态

利用这个性质打表

int N=1e6+10;
int fmax(int x)
{
    int m=0;
    while (x) {if (x%10>m) m=x%10; x/=10;}
    return m;
}
int fmin(int x)
{
    int m=10;
    while (x) {if (x%10<m&&x%10) m=x%10; x/=10;}
    return m;
}
bool sg[1000010];
void solve()
{
    for(int i=1;i<=9;i++) sg[i]=true;
    for(int i=10;i<=1000000;i++)
    {
        if(sg[i-fmax(i)]&&sg[i-fmin(i)]) sg[i]=false;
        else sg[i]=true;
    } 
    int q;
    cin>>q;
    while(q--)
    {
        int n;
        cin>>n;
        if(sg[n]) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

Alice Game

Problem - 7287 (hdu.edu.cn)

sg函数打表 

void get_sg() 
{
    int k;
    cin >> k;
    sg[0] = 0;
    for(int i = 1; i <= k; i++) sg[i] = 1;
    for(int i = k + 1; i <= 100; i++)// 打表
    {
        set<int> s;
        for(int left = 1; left < i; left++)//枚举左边有多少个
        {
            int right = i - k - left;
            if(left > 0 && right > 0) s.insert(sg[left] ^ sg[right]);
        }
        for(int mex=0;;mex++)
        {
            if(!s.count(mex)) sg[i]=mex;
        }
    }
    for(int i = 0; i <= 100; i++) 
    {
        cout << sg[i] << " "; 
    } 
}

C. Battle

Problem - 104385C - Codeforces

sg函数打表

bool sg(int x)
{
    if(f[x]!=-1) return f[x];
    set<int>s;
    for(int i=1;i<10;i++)
    {
        if(x>=pow(p,i)) s.insert(sg(x-pow(p,i)));
    }
    for(int i=0;;i++)
    {
        if(!s.count(i))
            return f[x]=i;
    }
}

#include <bits/stdc++.h>

using namespace std;

const int N = 110,M=3e5+10;
typedef long long ll;
ll x,p,n,res;

ll sg1(ll x)//x为奇数的情况
{
    return x%2;
}

ll sg2(ll x)//x为偶数的情况
{
    if(x==p) return 2;
    if(x%2==0) return 0;
    else return 1;
}

int main()
{
    res=0;
    cin>>n>>p;
    for(ll i=0;i<n;i++){
        cin>>x;
        if(p&1)
        {
            res^=sg1(x);
        }
        else
        {
            x%=(p+1);
            res^=sg2(x);
        }
    }
    if(res) cout<<"GOOD"<<'\n';
    else cout<<"BAD"<<'\n';
    return 0;
}

Distinct Numbers

C - Distinct Numbers (atcoder.jp)

假设有n个数,那么这个游戏的终态就是0、1、2、3……n-1

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值