HDU 5754 Life Winner Bo (博弈)

本文通过分析棋类游戏中皇后的走法规则,将其转化为威佐夫博弈问题,并提供了一种通过编程来解决该问题的方法。文中详细介绍了如何通过观察规律推导出必胜策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于 皇上、车、马的判断 画图多试几个例子应该不难发现;

但是皇后,有毒……比赛的时候推唯一的感觉就是,皇后P点(必胜点)好多啊!最后只推出来(2,3)(4,6)两个N点……

比赛完看见有人用word画图,又学到了……

再次画了一遍,大概就是下面那样,果然图画的好规律就好找


(n,m)点是必败点,在这个点,轮到谁走谁输。

在(n,m)引三条射线,线上的点显然都是P点,因为它们都可以在下一步到达一个N点,使对手必败。

引出三条射线后又发现了两个N点,即图中的(n-1,m-2)和(n-2,m-1),再给这两个点画上射线……

逐步发现图中其它所有N点。

然后观察规律

1)N点肯定都是成对出现的,也就是说有(2,3)就有(3,2)所以只需要考虑一边。

2)每行每列最多只有一个N点。

3)仔细观察,如果把(n,m)当做(1,1),倒推,N点分别是(2,3),(4,6),(5,8),(7,11)…… 看(i,j)的差值是从1开始递增的,而且i是从2开始,(2,4,5,7……)看到没有3和6,发现如果N点(i,j)出现过,那么就不会出现(j,x)这种情况(之前说过只考虑一边,即先忽略(3,2)),所以只要在打表的时候弄个标记数组就可以了。

所以就可以这样打表了!

int mp[2005][2005],vis[2005];
void init()
{
    mst(mp,0);
    mp[1][1]=1;
    for(int i=2,j=1;i<1005&&i+j<1005;i++,j++)
    {
        if(vis[i])
        {
            j--;
            continue;
        }
        mp[i][i+j]=mp[i+j][i]=1;
        vis[i]=vis[j+i]=1;
       // printf("%d %d %d\n",i,i+j,mp[i][j+i]);
    }
}
但是看到题解:

④皇后。

画画图后,我们可以将问题转化为:

“有两堆石子,每次可以在一堆里取任意(非空)颗(相当于是车的走法),或者在两堆里取相同(非空)颗(相当于是象的走法),取到最后一颗石子的人获胜,问先后手谁有必胜策略。”

百度发现这是多年前学过的威佐夫博弈:威佐夫博弈

我勒个去!

之前的观察规律推导差不多就是生生的把威佐夫博弈从无到有推了一遍。

【代码】

/* ***********************************************
Author        :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define mst(a,k)  memset(a,k,sizeof(a));
#define LL long long
#define maxn 1005
#define mod 100000007

int mp[2005][2005],vis[2005];
void init()
{
    mst(mp,0);
    mp[1][1]=1;
    for(int i=2,j=1;i<1005&&i+j<1005;i++,j++)
    {
        if(vis[i])
        {
            j--;
            continue;
        }
        mp[i][i+j]=mp[i+j][i]=1;
        vis[i]=vis[j+i]=1;
       // printf("%d %d %d\n",i,i+j,mp[i][j+i]);
    }
}
int main()
{

    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    init();
    int t,type,n,m;
    scan(t);
    while(t--)
    {
        scanf("%d%d%d",&type,&n,&m);
        if(type==1)
        {
           if( m%2==0 || n%2==0)
                puts("B");
           else
                puts("G");
        }
        else if(type==3)
        {
            if((m+n)%3 != 2 || abs(m-n)>1)
                puts("D");
            else
            {
                if(m!=n)
                    puts("B");
                else
                    puts("G");
            }
        }
        else if(type==2)
        {
            if(m==n)
                puts("G");
            else
                puts("B");
        }
        else
        {
            n--;m--;
            if(n>m) swap(n,m);
            m = (int) (m-n)*(sqrt(5)+1)/2; //威佐夫博弈
            if(m==n)
            //if(mp[n][m])  //打表也可
                puts("G");
            else
                puts("B");

        }

    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值