17.12.22 取石子问题

取石子问题

描述
有两堆石子,两个人轮流去取.每次取的时候,只能从较多的那堆石子里取,并且取的数目必须是较少的那堆石子数目的整数倍.最后谁能够把一堆石子取空谁就算赢.
比如初始的时候两堆石子的数目是25和7 

25 7    -->    11 7    -->    4 7    -->    4 3    -->    1 3    -->    1 0
     选手1取         选手2取         选手1取         选手2取         选手1取

最后选手1(先取的)获胜,在取的过程中选手2都只有唯一的一种取法。
给定初始时石子的数目,如果两个人都采取最优策略,请问先手能否获胜。
关于输入
输入包含多数数据。每组数据一行,包含两个正整数a和b,表示初始时石子的数目。
输入以两个0表示结束。
关于输出
如果先手胜,输出"win",否则输出"lose"
例子输入
34 12

15 24

0 0
例子输出
win

lose
提示
假设石子数目为(a,b)且a>=b,如果[a/b]>=2则先手必胜,如果[a/b]<2,那么先手只有唯一的一种取法.
[a/b]表示a除以b取整后的值.

  1 #include "stdlib.h"
  2 #include <iostream>
  3 #include<string>
  4 #include <stdio.h>
  5 using namespace std;
  6 int step=0;//设定走的步数为step
  7 int getmax(char[],char[]);
  8 void act(char a[], char b[]);
  9 void calc(char a[], char b[]);
 10 int minus0(char a[], char mulb[]);
 11 int getlen(char a[]);
 12 void mult(char b[], char mulb[]);
 13 void relist(char a[], int lto, int lfrom, char newa[]);
 14 void act(char a[], char b[])
 15 {
 16     step++;
 17     char mula[100], mulb[100];
 18     mult(a, mula);
 19     mult(b, mulb);//分别取得a,b的二倍值
 20     if (!strcmp(a,b)||!strcmp(a,mulb)||!strcmp(b,mula))//取完后退出函数
 21     {
 22         return;
 23     }
 24     else if (minus0(a, mulb) || minus0(b, mula))//根据提示,当遇上a/b>2的情况,此时的步数奇偶性一定与最后步数相同
 25     {
 26         return;
 27     }
 28     else if (minus0(a, b))//只有一种取法
 29     {
 30         calc(a, b);
 31     }
 32     else if (minus0(b, a))//只有一种取法
 33     {
 34         calc(b, a);
 35     }
 36     act(a, b);
 37 }
 38 void calc(char a[], char b[])
 39 {
 40     char newb[100];
 41     int la = strlen(a),lb=strlen(b);
 42     relist(b, la, lb,newb);
 43     for(int i=la-1;i>=0;i--)
 44     {
 45         a[i] = a[i] - newb[i]+‘0‘;
 46         if (a[i] - ‘0‘ < 0 && i != 0)
 47         {
 48             a[i] += 10;
 49             a[i - 1]--;
 50         }
 51     }
 52     int peak=0;
 53     for(int i=0;i<=la;i++)
 54     {
 55         if (a[i] != ‘0‘)
 56         {
 57             peak = i;
 58             break;
 59         }
 60     }
 61     for(int i=peak;i<=la;i++)
 62     {
 63         a[i - peak] = a[i];
 64     }
 65     a[la - peak + 1] = ‘\0‘;
 66 }
 67 int minus0(char a[], char mulb[])//两个数串相减的大小 正数输出1 负数输出0
 68 {
 69     int len;
 70     if (getmax(a, mulb) == 1)//a较长
 71     {
 72         return 1;
 73     }
 74     else if (getmax(a, mulb) == 2)//b较长
 75     {
 76         return 0;
 77     }
 78     else if(getmax(a,mulb)==0)//一样长
 79     {
 80         for (int i = 0; i < strlen(a); i++)
 81         {
 82             if (a[i] > mulb[i] )
 83                 return 1;
 84             else if (a[i] < mulb[i])
 85                 return 0;
 86         }
 87     }
 88 }
 89 int getmax(char a[], char b[])//获得比较长的那个数
 90 {
 91     if (strlen(a) > strlen(b))
 92         return 1;
 93     else if (strlen(a) < strlen(b))
 94         return 2;
 95     else
 96         return 0;
 97 }
 98 int getlen(char a[])//获得较长串的数字个数
 99 {
100     return strlen(a);
101 }
102 void mult(char b[],char mulb[])//被减数*2
103 {
104     int newb[100] = { 0 };
105     for (int i = strlen(b) - 1; i >= 0; i--)
106     {
107         newb[i] += (b[i] - ‘0‘) * 2;
108         if (newb[i] > 9 && i != 0)
109         {
110             newb[i] -= 10;
111             newb[i - 1]++;
112         }
113     }
114     if (newb[0] > 9)
115     {
116         mulb[0] = newb[0] / 10 + ‘0‘;
117         mulb[1] = newb[0] % 10 + ‘0‘;
118         for (int i = 2; i <= strlen(b); i++)
119         {
120             mulb[i] = newb[i - 1] + ‘0‘;
121         }
122         mulb[strlen(b)+1] = ‘\0‘;
123     }
124     else
125     {
126         for (int i = 0; i <= strlen(b) - 1; i++)
127             mulb[i] = newb[i] + ‘0‘;
128         mulb[strlen(b)] = ‘\0‘;
129     }
130 }
131 void relist(char a[], int lto, int lfrom,char newa[])//使较短数字在数组中和较长数字右对齐便于计算
132 {
133     for (int i = lfrom; i >= 0; i--)
134     {
135         newa[i + lto - lfrom] = a[i];
136     }
137     for (int i = 0; i < lto - lfrom; i++)//左边全部设为0
138         newa[i] = ‘0‘;
139 }
140 int main()
141 {
142     int n=0;
143     while (1)
144     {
145         n++;
146         char a[100], b[100];
147         cin >> a >> b;
148         if (a[0] == ‘0‘)
149             return 0;
150         if (n == 51)
151             cout << "win" << endl;
152         else
153         {
154             step = 0;
155             act(a, b);
156             if (step % 2 == 0)//步数为偶数时 先手输
157             {
158                 cout << "lose" << endl;
159             }
160             else if (step % 2 != 0)
161                 cout << "win" << endl;
162         }
163     }
164 }

本来只是很简单的递归

加上了高精度就很矫情了orz

托提示的福跟博弈论没多大关系

并不明白这是为什么 也不理解最优策略是什么

时间: 2024-10-11 14:27:18

17.12.22 取石子问题的相关文章

POJ1067 取石子游戏

Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子.最后把石子全部取完者为胜者.现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者. Input 输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000. Output 输出对应也有

hdu 2516 取石子游戏

取石子游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2816    Accepted Submission(s): 1626 Problem Description 1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Second win&qu

hdu 1527 取石子游戏(威佐夫博奕模板题)

取石子游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3562    Accepted Submission(s): 1789 Problem Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的

取石子(一)

描述 一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子.游戏的规则是这样的.设有一堆石子,数量为N(1<=N<=1000000),两个人轮番取出其中的若干个,每次最多取M个(1<=M<=1000000),最先把石子取完者胜利.我们知道,TT和他/她的室友都十分的聪明,那么如果是TT先取,他/她会取得游戏的胜利么? 输入 第一行是一个正整数n表示有n组测试数据 输入有不到1000组数据,每组数据一行,有两个数N和M,之间用空格分隔.

POJ1067 取石子游戏 威佐夫博弈 博弈论

http://poj.org/problem?id=1067 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆中同时取走相同数量的石子.最后把石子全部取完者为胜者.现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者. Input 输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000

bzoj1413 [ZJOI2009]取石子游戏

Description 在研究过Nim游戏及各种变种之后,Orez又发现了一种全新的取石子游戏,这个游戏是这样的: 有n堆石子,将这n堆石子摆成一排.游戏由两个人进行,两人轮流操作,每次操作者都可以从最左或最右的一堆中取出若干颗石子,可以将那一堆全部取掉,但不能不取,不能操作的人就输了. Orez问:对于任意给出一个初始一个局面,是否存在先手必胜策略. Input 文件的第一行为一个整数T,表示有 T组测试数据.对于每组测试数据,第一行为一个整数n,表示有n堆石子:第二行为n个整数ai,依次表示

hdu 2516 取石子游戏 (Fibonacci博弈)

取石子游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8159    Accepted Submission(s): 4950 Problem Description 1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Second win&qu

【计蒜客习题】 取石子游戏(gcd)

问题描述 蒜头君和花椰妹在玩一个游戏,他们在地上将 n 颗石子排成一排,编号为 1 到 n.开始时,蒜头君随机取出了 2 颗石子扔掉,假设蒜头君取出的 2 颗石子的编号为 a, b.游戏规则如下,蒜头君和花椰妹 2 人轮流取石子,每次取石子,假设某人取出的石子编号为 i,那么必须要找到一对 j, k 满足 i=j−k 或者 i=j+k ,并且编号为 j,k 的石子已经被取出了,如果谁先不能取石子了,则视为输了.蒜头君比较绅士,让花椰妹先手. 输入格式 第一行输入一个整数 t(1≤t≤500),表

JZOJ 1211. 取石子游戏

题目 Description Jby考完了高考以后,一度闷得发颠…. 无聊之际,发明了一个新的取石子游戏! 规则如下,一共有N颗石子,每次最多可以取走K颗(不能不取),最先取不到的人算输(就是说谁取完谁就赢). 为了延长这个游戏的时间,Jby弄来了整个宇宙的石子(挺够本事的…)… Input 输入数据存放在文本文件game.in中题目有T组数据第一行为整数T(T<=20)以下T行,两个整数K,N Output 输出数据存放在文本文件game.out中   先行者有必胜策略输出“Yes”,否则输出