17.12.22 取石子問題
阿新 • • 發佈:2017-12-23
isp 數組 技術分享 [] ostream none 取石子 -s src
取石子問題
描述
有兩堆石子,兩個人輪流去取.每次取的時候,只能從較多的那堆石子裏取,並且取的數目必須是較少的那堆石子數目的整數倍.最後誰能夠把一堆石子取空誰就算贏.
比如初始的時候兩堆石子的數目是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;//設定走的步數為stepView Code7 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
托提示的福跟博弈論沒多大關系
並不明白這是為什麽 也不理解最優策略是什麽
17.12.22 取石子問題