取石子问题
描述
有两堆石子,两个人轮流去取.每次取的时候,只能从较多的那堆石子里取,并且取的数目必须是较少的那堆石子数目的整数倍.最后谁能够把一堆石子取空谁就算赢.
比如初始的时候两堆石子的数目是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
托提示的福跟博弈论没多大关系
并不明白这是为什么 也不理解最优策略是什么