石头剪刀布(C++)
题目描述
wzms 今年举办了一场剪刀石头布大赛,bleaves 被选为负责人。
比赛共有 个人参加, 分为 n 轮,在每轮中,第 1 位选手和第 2 位选手对战,胜者作为新的第 1 位选手,第 3 位和第 4 位对战,胜者作为新的第 2 位选手,以此类推。
bleaves 调查得知,每个人都有其偏爱决策,每个人在每一次对战中都会使用他的偏爱决策。
如果一次对战的双方的偏爱决策相同,那么这次对战就永远不会结束,所以 bleaves 不希望这种情况发生。
现在 bleaves 知道了每个人的偏爱决策,但她不知道如何安排初始的次序,使得上面的情况不会发生,你能帮帮她吗?
输入描述:
一行三个整数 R,P,S ,表示偏爱石头,布,剪刀的人数分别为 R,P,S 。
输出描述:
如果无解,输出 IMPOSSIBLE
;
否则输出一个长度为 R+P+S 的字符串,第 i 个字符表示初始时第 i 位选手的偏爱决策,
如果有多种方案,输出字典序最小的。
示例1
输入
1 1 0
输出
PR
说明
只有 2 个选手,一个偏爱石头,一个偏爱布,无论次序如何,偏爱布的选手都会胜出。
所以方案可以是 PR 和 RP ,其中字典序最小的 PR 。
示例2
输入
2 0 0
输出
IMPOSSIBLE
示例3
输入
1 1 2
输出
PSRS
备注:
全部的输入数据满足:
题目思路:
反向思考。
只要确定了最终胜出的人,那么前面的都能推出来了,那么就从最后往前递归,然后从末尾往前按字典序排序递归回来。
时间
解题代码:
#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;
}