学习笔记:博弈问题(一)

一.bash game

题目一般是这样:有一堆n个物品,两人轮流取,每次至少取一个,最多取m个,最后取光的人获胜。问如果你先取,你取多少就能获胜。

我们可以想一下,如果是(m+1)个物品,你无论取多少个,最后都是对方取完(最多取m个),比如,你取1,对方取m,你取2,对方取m-1,是不是无论你取多少个,对方都一定能赢。

那么反过来,我们是想赢的那个人,怎么反过来呢?如果我们能让物品为(m+1)+k个,我们第一次取k个,他第一次不论取多少,最后一次的我们都能取完。

这样的话,我们就让每个取的回合的物品都为m+1,然后就有这样的一个式子

n=(m+1)*r+s,其中r是回合数,如果s=0,那么我先取的话,对方一定赢,如果s>=1,那么我们一定能赢。

来道十分裸的例题:HDU 1846

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        int mod=n%(m+1);//这里的mod就是s
        if(mod==0)
            cout<<"second"<<endl;
        else
            cout<<"first"<<endl;
    }
    return 0;
}

二.Fibinacci's game

一共有n个石子,双方轮流取,规则:(1).先手不能在第一次把所有石子取完(2).之后每次可以取的石子数是从1到对手取的石子数的两倍之间(包含两倍)。

我们用到一个结论:如果石子总数n是斐波那契数那么后手赢,反之先手赢。(可以自己模拟一遍)

裸题是HDU 2516

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int main()
{
    int fib[50]={0};
    fib[0]=2;fib[1]=3;
    for(int i=2;i<50;i++)
        fib[i]=fib[i-1]+fib[i-2];
   int n;
   while(cin>>n&&n)
   {
       int flag=0;
       for(int i=0;i<50;i++)
       {
           if(n==fib[i])
            flag=1;
           if(n<fib[i])
            break;
       }
       if(flag==1)
        puts("Second win");
       else
        puts("First win");
   }
   return 0;
}

三.Wythoff game

从两堆的若干个物品中,两人轮流从一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者胜。

这里我们会面对一个奇异局势,我们用(ak,bk)(ak<=bk,k=0,1,....,n),来表示两堆物品的数量并称其为局势,如果甲面对的是(0,0)那么甲一定输,或者甲面对(1,2),甲不论取走多少都会输,比如从a堆取1,从b堆取1,乙取完剩下;从a堆取1,乙取完剩下;从b堆取2,乙取完剩下;从b堆取1,乙取完剩下。我们把这样一种局势成为奇异局势。

像这样的奇异局势有(0,0),(1,2),(3,5),(4,7),(6,10),(8,13),(9,15),(10,17)......

可以看出a0=b0=0,ak是在前面未出现的最小自然数,比如(0,0)之后未出现的最小的是1,所以是(1,2),此时已经出现了0,1,2,所以下一个最小的自然数是3,就是(3,5)。bk=ak+k,b1=a1+1=1+1=2,所以是(1,2),b2=a2+2=3+2=5,所以是(3,5)。

如果面对非奇异局势,那么先拿者必胜,如果面对奇异局势,那么后拿者必胜。

有一个Betty定理:设a、b是正无理数且 1/a +1/b =1。记P={ [na] | n为任意的正整数},Q={ [nb] | n 为任意的正整数},([x]'指的是取x的整数部分)则P与Q是Z+的一个划分,即P∩Q=∅且P∪Q=Z+。

根据Betty定理我们知道上述矩阵中每一行第一列的数为[∅i],第二列的数为[(∅+1)i],其中∅=(sqrt(5)+1)/2为黄金分割比。

任给一个局势(a,b),怎么判断是不是奇异局势?如下:

ak=[k(1+√5 )/2],bk=ak+k(k=0,1,.....,n)

k=bk-ak;

如果ak=[(b-a)*(1+√5 )/2]那么就是奇异局势,否则不是。

裸题:POJ 1067

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    int a,b;
    while(cin>>a>>b)
    {
        if(a>b)
            swap(a,b);
        int c=floor((b-a)*(sqrt(5.0)+1)/2);
        if(a==c)
        puts("0");
        else
        puts("1");
    }
    return 0;
}

四.Nimm game

有n堆若干个物品,两人任意从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

我们用(a,b,c)表示某种局势,(0,0,0)显然是奇异局势,第二种是(0,n,n)只要与对手拿走同样多的物品,最后都会变成(0,0,0)的情况,所以也是奇异局势。(1,2,3)也是奇异局势,不论怎么拿都可以将它变成(0,n,n)的奇异局势。

怎么判断(x,y,z)是奇异局势呢?

借助异或运算。比如(1,2,3)

1 二进制 01,2的二进制是10,1和2异或是11,再和3  即11异或结果为0 0.

怎么让一个非奇异局势变成一个奇异局势呢?

比如假设(a,b,c)为非奇异局势,咱们用这么一个公式:a⊕ b⊕ (a⊕ b)=(a⊕ a)⊕ (b⊕ b)=0⊕ 0=0,那么我们把这个c变为a⊕ b,就能将(a,b,c)变为奇异局势,即变成c-(c-(a⊕ b))=c-c+(a⊕ b)=a⊕b.那么我们从c中拿多少才能变成奇异局势呢,即拿走c-(a⊕ b)。

例题HDU 1850(这道题是这样想的:如果你先手能赢则m个数异或的结果不为0,那肯定是存在拿走了某个数使之能成为一个奇异局势,假设n个数中存在一个数a,从a中拿走a-除a以外的那n-1个数的异或值,就能使之成为奇异局势,那么a一定是大于那n-1个数的异或值的,所以我们就找满足这样的a有多少个,就是你第一步可行的方案数)

#include<bits/stdc++.h>
using namespace std;
int a[110];
int main()
{
    int m;
    while(cin>>m&&m)
    {
        int ans=0,cnt=0;
        for(int i=0;i<m;i++)
        {
            cin>>a[i];
            ans^=a[i];
        }
        if(ans==0)
            puts("0");
        else
        {
            for(int i=0;i<m;i++)
            {
                int k=ans^a[i];
                if(k<a[i])
                    cnt++;
            }
            cout<<cnt<<endl;
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值