1. 程式人生 > >17.12.22 取石子問題

17.12.22 取石子問題

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;//設定走的步數為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 取石子問題