石头剪刀布(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; }