2177博弈问题 取石子游戏

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2177

相关算法:http://blog.csdn.net/a0210077/archive/2010/01/22/5223105.aspx

 

#include <iostream>
#include <queue>
using namespace
std;

const
double d=1.6180339887498948482045;    //黄金矩形的长宽比
const int MAX=381967;
int
t[MAX+1][2]={{0,0}};    //共有381968个必输组合,{0,0}算输,[差距][石子]
int a,b,margin;
int
i,j,temp;

void
count(){  //计算必输组合
    temp=0,i=1;
    a=1,b=2;
    queue<int>q;
    while
(b<=1000000){
        q.push(b);
        t[i][0]=a;
        t[i][1]=b;
        if
(a>temp){
            temp=q.front();
            q.pop();
        }

        if
(a+1==temp){
            a+=2;
            b+=3;
        }
else{
            a++;
            b+=2;
        }

        i++;
    }
}



void
search(int now, int take){
    bool
found=false;
    i=int(now/d);    //搜索前数
    while(i<=MAX && t[i][0]<=now){
        if
(t[i][0]==now){
            found=true;
            break
;
        }

        i++;
    }

    if
(!found){
        i=int(now/d/d);    //搜索后数
        while(i<=MAX && t[i][1]<=now){
            if
(t[i][1]==now){
                found=true;
                break
;
            }

            i++;
        }
    }

    if
(found){
        if
(t[i][0]==now && t[i][1]<take || t[i][1]==now && t[i][0]<take)    //判断是否真的取走石子
            printf("%d %d/n",t[i][0],t[i][1]);
    }
}


void
result(){
    if
(margin!=0 && margin<=MAX && a==t[margin][0] && b==t[margin][1]) //判断是否为必输状态,差距超过381968判定为胜利
        printf("0/n");
    else
{
        printf("1/n");
        if
(margin<=MAX && a>t[margin][0])    //是否能2堆石子一起取,达到必输状态
            printf("%d %d/n",t[margin][0],t[margin][1]);
        if
(a==2 && b==2){        //除开2,2,当2堆石子数相同时不存在取1堆石子到达必输状态
            printf("1 2/n");
        }
else if (margin!=0){
            search(a,b);    //搜索小堆石子不动,取大堆石子的方案
            search(b,a);    //搜索大堆石子不动,取小堆石子的方案
        }
    }   
}


int
main(int argc, char* argv[])
{

    count();
    while
(1){
        scanf("%d%d",&a,&b);
        if
(a==0 && b==0)
            break
;
        if
(a>b){    //a小b大
            temp=a;
            a=b;
            b=temp;
        }

        margin=b-a;
        result();
    }

    return
0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值