石頭剪刀布(C++)
點擊作題網站連接ios
題目描述
wzms 今年舉辦了一場剪刀石頭布大賽,bleaves 被選爲負責人。
比賽共有 2n2^n2n 我的參加, 分爲 n 輪,在每輪中,第 1 位選手和第 2 位選手對戰,勝者做爲新的第 1 位選手,第 3 位和第 4 位對戰,勝者做爲新的第 2 位選手,以此類推。
bleaves 調查得知,每一個人都有其偏心決策,每一個人在每一次對戰中都會使用他的偏心決策。
若是一次對戰的雙方的偏心決策相同,那麼此次對戰就永遠不會結束,因此 bleaves 不但願這種狀況發生。
如今 bleaves 知道了每一個人的偏心決策,但她不知道如何安排初始的次序,使得上面的狀況不會發生,你能幫幫她嗎?網站
輸入描述:
一行三個整數 R,P,S ,表示偏心石頭,布,剪刀的人數分別爲 R,P,S 。url
輸出描述:
若是無解,輸出 IMPOSSIBLE
;
不然輸出一個長度爲 R+P+S 的字符串,第 i 個字符表示初始時第 i 位選手的偏心決策,
若是有多種方案,輸出字典序最小的。spa
示例1
輸入
1 1 0.net
輸出
PRcode
說明
只有 2 個選手,一個偏心石頭,一個偏心布,不管次序如何,偏心布的選手都會勝出。
因此方案能夠是 PR 和 RP ,其中字典序最小的 PR 。排序
示例2
輸入
2 0 0遞歸
輸出
IMPOSSIBLEci
示例3
輸入
1 1 2字符串
輸出
PSRS
備註:
所有的輸入數據知足:
R+P+S=2n,1≤n≤20R+P+S=2^n ,1≤n≤20R+P+S=2n,1≤n≤20
題目思路:
反向思考。
只要肯定了最終勝出的人,那麼前面的都能推出來了,那麼就從最後往前遞歸,而後從末尾往前按字典序排序遞歸回來。
時間 O(2n×n)O(2^n×n)O(2n×n)
解題代碼:
#include <iostream> #include <string> using namespace std; int dfs1(int R,int P,int S)//石頭,布,剪刀 { if( R < 0 || P < 0 || S < 0 ) return -1;//有一類人數爲負數即無解 if( R==0 && P==0 && S==0 ) return -1;//沒有人蔘加比賽也無解 if( R==1 && P==0 && S==0 ) return 0;//石頭贏 if( R==0 && P==1 && S==0 ) return 1;//布贏 if( R==0 && P==0 && S==1 ) return 2;//剪刀贏 return dfs1( (R-P+S)>>1,(R+P-S)>>1,(-R+P+S)>>1 );//遞歸(>>1:位運算,即除以2) } string dfs2(int t,int p) { if( p==1 )//當參賽只有2人時 { if( t==0 ) return "RS";//石頭贏 else if( t==1 ) return "PR";//布贏 else return "PS";//剪刀贏 } if( t==0 )//當石頭贏時(參賽者2人以上) { //既然這把是石頭贏了,那這一局確定是石頭和剪刀的對決 //那麼上一局對決的兩組確定是:石頭和剪刀,剪刀和布,纔可能獲得這一局的石頭和剪刀 string s1 = dfs2(2,p>>1);//遞歸,上一把是剪刀和布的對決,剪刀勝利 string s2 = dfs2(0,p>>1);//遞歸,上一把是石頭和剪刀的對決,石頭勝利 if( s1.compare(s2)>0 ) return s2+s1;//要求輸出字典序最小的 else return s1+s2; } else if( t==1 )//當布贏時(參賽者2人以上) { //既然這把是布贏了,那這一局確定是布和石頭的對決 //那麼上一局對決的兩組確定是:布和石頭,石頭和剪刀,纔可能獲得這一局的布和石頭 string s1 = dfs2(1,p>>1);//遞歸,上一把是布和石頭的對決,布勝利 string s2 = dfs2(0,p>>1);//遞歸,上一把是石頭和剪刀的對決,石頭勝利 if( s1.compare(s2)>0 ) return s2+s1;//要求輸出字典序最小的 else return s1+s2; } else//當剪刀贏時(參賽者2人以上) { //既然這把是剪刀贏了,那這一局確定是剪刀和布的對決 //那麼上一局對決的兩組確定是:剪刀和布,布和石頭,纔可能獲得這一局的剪刀和布 string s1 = dfs2(1,p>>1);//遞歸,上一把是布和石頭的對決,布勝利 string s2 = dfs2(2,p>>1);//遞歸,上一把是剪刀和布的對決,剪刀勝利 if( s1.compare(s2)>0 ) return s2+s1;//要求輸出字典序最小的 else return s1+s2; } } int main() { int R,P,S;//石頭,布,剪刀 cin >> R >> P >> S; int t = dfs1(R,P,S); if( t==-1 ) { cout<<"IMPOSSIBLE"<<endl; return 0; } string s = dfs2( t,(R+P+S)>>1 );//反向思考,根據結果還原每一輪。人數都是每一輪除以2 cout << s << endl; }
筆記:
關於 s1.compare(s2) 的用法:
- 字符串比較:
#include <iostream> #include <string> using namespace std; int main() { string s1,s2; cin >> s1 >> s2; if( s1.compare(s2)>0 ) cout << "s1>s2" << endl; else if( s1.compare(s2)<0 ) cout << "s1<s2" << endl; else cout << "s1==s2" << endl; }
- 子串比較:
#include <iostream> #include <string> using namespace std; int main() { string s1 = "hello,world!"; string s2 = "hello"; //從s1的下標0的字符開始,包含5個字符與s2整個字符串比較 if( s1.compare(0,5,s2)==0 ) cout << "從s1的下標0的字符開始,包含5個字符,即'hello'等於s2整個字符串" << endl; else cout << "s1的指定子串不等於s2" << endl; //s1指定子串與s2的指定子串進行比較 if( s1.compare(3,4,s2,3,4)==0 ) cout << "s1的指定子串等於s2的指定子串" << endl; else cout << "s1的指定子串不等於s2的指定子串" << endl; //s1指定子串與字符串的前n個字符進行比較 if(s1.compare(0,2,"hell",2)==0) cout << "s1的指定子串等於指定字符串的前2個字符組成的子串" << endl; else cout << "s1的指定子串不等於指定字符串的前2個字符組成的子串" << endl; }