6F.石頭剪刀布(C++)

石頭剪刀布(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=2n1n20

題目思路:

反向思考。
只要肯定了最終勝出的人,那麼前面的都能推出來了,那麼就從最後往前遞歸,而後從末尾往前按字典序排序遞歸回來。
時間 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) 的用法:

  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; 
}
相關文章
相關標籤/搜索