zoukankan      html  css  js  c++  java
  • 一本通网站1132:石头剪子布

    【题目描述】
    石头剪子布,是一种猜拳游戏。起源于中国,然后传到日本、朝鲜等地,随着亚欧贸易的不断发展它传到了欧洲,到了近现代逐渐风靡世界。
    简单明了的规则,使得石头剪子布没有任何规则漏洞可钻,单次玩法比拼运气,多回合玩法比拼心理博弈,使得石头剪子布这个古老的游戏
    同时用于“意外”与“技术”两种特性,深受世界人民喜爱。 游戏规则:石头打剪刀,布包石头,剪刀剪布。 现在,需要你写一个程序来判断石头剪子布游戏的结果。 【输入】 第一行是一个整数N,表示一共进行了N次游戏。1 ≤ N ≤ 100。 接下来N行的每一行包括两个字符串,表示游戏参与者Player1,Player2的选择(石头、剪子或者是布): S1 S2 字符串之间以空格隔开S1,S2只可能取值在{"Rock", "Scissors", "Paper"}(大小写敏感)中。 【输出】 输出包括N行,每一行对应一个胜利者(Player1或者Player2),或者游戏出现平局,则输出Tie。 【输入样例】 3 Rock Scissors Paper Paper Rock Paper 【输出样例】 Player1 Tie Player2

      分析:这个题目难度不大,完全可以暴力解决,如果完全无脑算法也还可以接受,最多9种对决情况。暴力列出9种对决情况的算法在这里就不啰嗦了,如果从结题判断,那最终只有三种结果,故可以暴力列举三种结果,当然,每一种结果仍然可能包含多种情况。在这三种情况中,平局最简单——两个选手出相同手势(其实这里面包含了三种情况,但判断语句都一样),再列出一种,另一种直接else就好。比如,列举Player1胜Player2,那就需要列出三种对决的完整情形。可得到如下代码:

    //1132:石头剪子布第一版本:完整暴力列举 
    #include<iostream>
    using namespace std;
    int main()
    {
        int n;
        string p1,p2;
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            cin>>p1>>p2;
            if(p1=="Rock"&&p2=="Scissors"||p1=="Scissors"&&p2=="Paper"||p1=="Paper"&&p2=="Rock")
            {
                cout<<"Player1
    ";
            }
            else if(p1==p2)
            {
                cout<<"Tie
    ";
            }
            else cout<<"Player2
    ";
        }
         return 0;
    }
    第一版本

      在第一版本里可以做一点小优化,我们注意到三个单词的首字母不用,故我们也可以直接用首字母判断即可,这样可避免字母太多,出现拼写错误。于是有了第二版本:

    //1132:石头剪子布第二版本-部分暴力列举 
    #include<iostream>
    using namespace std;
    int main()
    {
        int n;
        char p1[10],p2[10];
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            cin>>p1>>p2;
            if(p1[0]=='R'&&p2[0]=='S'||p1[0]=='S'&&p2[0]=='P'||p1[0]=='P'&&p2[0]=='R')
            {
                cout<<"Player1
    ";
            }
            else if(p1[0]==p2[0])
            {
                cout<<"Tie
    ";
            }
            else cout<<"Player2
    ";
        }
         return 0;
    }
    第二版本

      对于C++编程,我们还要学会模块化编程思想,即可以把一些特定的功能编成一个函数,这些可以提高代码的利用率,也可以增加程序的可读性和减少程序维护代价。对本题而言,我们完全可以把判断过程写成一个函数,这样可以大大减少主程序的复杂度,特别是在以后程序变得更加复杂后,模块化是必然趋势。于得得到第三版本:

    //1132:石头剪子布第三版本-普通函数 
    #include<iostream>
    using namespace std;
    string rsp(string p1,string p2)
    {
        string rerult;
        if(p1[0]=='R'&&p2[0]=='S'||p1[0]=='S'&&p2[0]=='P'||p1[0]=='P'&&p2[0]=='R')
        {
            rerult="Player1
    ";
        }
        else if(p1==p2)
        {
            rerult="Tie
    ";
        }
        else rerult="Player2
    ";
        return rerult;            
     } 
    int main()
    {
        int n;
        string p1,p2;
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            cin>>p1>>p2;
            cout<<rsp(p1,p2);
        }
         return 0;
    }
    第三版本

      如果,我们对这一个问题再做一个更深入的思考,不难发现,P1胜P2的情况很有规律性,如果把石头、剪刀、布放在一个圆圈上,按照一定的方向便是胜/败的判断依据。这里的“圆圈”实质上可以理解为周期性出现。最终结果只有三种,那我们可以想到任何一个整数除以3的余数也只有三种情况(0、1、2),那是否可以考虑对石头、剪刀、布数字化,依次赋值为1,2,3。那我们不难得出:p1胜p2<==>p1的对应值-p2对应值=-1或2,从余数角度完全可以是同一个。为了解决负数问题,我们先加一个3,再对3取余数,那-1和2是等价的了,都将转换成2。至此,程序便可以修改为第四版本:

    //1132:石头剪子布第四版本-赋值函数 
    #include<iostream>
    using namespace std;
    int rsp(string s)
    {
        if(s[0]=='R') return 1;
        if(s[0]=='S')return 2;
        return 3;
    }
    int main()
    {
        int n;
        string p1,p2;
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            cin>>p1>>p2;
            if(p1==p2)cout<<"Tie
    ";
            else if((rsp(p2)-rsp(p1)+3)%3==1)cout<<"Player1
    ";
            else cout<<"Player2
    ";
        }
         return 0;
    }
    第四版本

      再对照上例中(rsp(p2)-rsp(p1)+3)%3这一个表达式可能出现的值为0、1、2,而我们最终结果也正好是三种,那我们可以把三种结果存入数组,用(rsp(p2)-rsp(p1)+3)%3做下标,直接调用结果,于是便有第五版本:

    //1132:石头剪子布第五版本-数组函数 
    #include<iostream>
    using namespace std;
    int rsp(string s)
    {
        if(s[0]=='R') return 1;
        if(s[0]=='S')return 2;
        return 3;
    }
    int main()
    {
        int n;
        string p1,p2,rerult[3]={"Tie
    ","Player1
    ","Player2
    "};
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            cin>>p1>>p2;
            cout<<rerult[(rsp(p2)-rsp(p1)+3)%3];
        }
         return 0;
    }
    第五版本

      当然,随着我们学习的深入,我们发现,“数字化”的想法已经不是我们首创,这些想法C++已经都想到了,并作出了很系统的模板封装好,我们只需直接调用便是——那就是功能强大的STL库函数。在这个题中的自编函数可用map来解决,看第六版本:

    //1132:石头剪子布第六版本-STL库函数 
    #include<iostream>
    #include<map> 
    using namespace std;
    int main()
    {
        int n;
        string p1,p2;
        string rerult[3]={"Tie
    ","Player1
    ","Player2
    "};;
        map<string,int> rsp;
        rsp["Rock"]=1;
        rsp["Scissors"]=2;
        rsp["Paper"]=3;
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            cin>>p1>>p2;
            cout<<rerult[(rsp[p2]-rsp[p1]+3)%3];
        }
         return 0;
    }
    第六版本

      写这么多,主要想让新学者体验一个程序的修改过程、优化过程,高手们也请多多指教,以便让我和新手们一起学学。

  • 相关阅读:
    linux 常用快捷键
    命令行远程链接
    mybatis参数错误 Parameter '×××' not found. Available parameters are [0, 1, param1, param2]
    mybatis延迟加载
    mybatis跨XML引用
    eclipse修改项目名称
    wait, WIFEXITED, WEXITSTATUS
    进程通信中如何进行值得传递?
    fork新建进程
    Ubuntu安装genymotion模拟器步骤
  • 原文地址:https://www.cnblogs.com/wendcn/p/12952740.html
Copyright © 2011-2022 走看看