1. 程式人生 > 實用技巧 >模擬賽9.4

模擬賽9.4

點選跳轉

#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;
}