17.12.22 取石子问题

Posted TobicYAL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
View Code

本来只是很简单的递归

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

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

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

以上是关于17.12.22 取石子问题的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1067 取石子游戏

USTC 1213取石子游戏(尼姆博弈)

(HDU - 1527)取石子游戏(斐波那契博弈)

[BZOJ3895]取石子

[BZOJ3895]取石子

nyoj 135 取石子 NIM