• 6F.石头剪刀布(C++)


    石头剪刀布(C++)

    点击做题网站链接

    题目描述
    wzms 今年举办了一场剪刀石头布大赛,bleaves 被选为负责人。
    比赛共有 2n2^n 个人参加, 分为 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

    备注:
    全部的输入数据满足:
    R+P+S=2n1n20R+P+S=2^n ,1≤n≤20

    题目思路:

    反向思考。
    只要确定了最终胜出的人,那么前面的都能推出来了,那么就从最后往前递归,然后从末尾往前按字典序排序递归回来。
    时间 O(2n×n)O(2^n×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) 的用法:

    1. 字符串比较:
    #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;
    }
    
    1. 子串比较:
    #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; 
    }
    
  • 相关阅读:
    许多其他C++的class样本
    cocos2d-x 3.2 它 2048 —— 第三
    hdu 4035 可能性DP 成都网络游戏
    OpenWrt 主的发展版本号trunk MT7620N 无线驱动程序bug
    [leetcode]Permutation Sequence
    Java Swing编程接口(30)---列表框:JList
    [创新工场]2014创新工场校园招聘回文字符串维修
    FFmpeg来源简单分析:结构会员管理系统-AVClass
    [Angular 2] Component relative paths
    [TypeScript] Reflection and Decorator Metadata
  • 原文地址:https://www.cnblogs.com/yuzilan/p/10626102.html
Copyright © 2020-2023  润新知