题意:一共三种人,喜欢石头、剪刀、布,设定为喜欢石头的和喜欢剪刀的玩,喜欢石头的赢,以此类推。设一共 2 n 2^n 2n 个人,编号为 1 1 1, 2 2 2, 3 3 3,…, 2 n 2^n 2n,其中第一轮 1 1 1 和 2 2 2 比,然后胜者与 3 3 3 和 4 4 4 的胜者比,一轮一轮下去直到只剩一个人,现在给定 2 n 2^n 2n 个人的喜好,问如何安排编号顺序,能保证比赛进行过程中不会出现喜好相同的人进行比赛。
思路:设某一轮可行解为 a a a 个石头, b b b 个剪刀, c c c 个布,可以退出上一轮可行解为 a + c a+c a+c 个石头, a + b a+b a+b 个剪刀, b + c b+c b+c个布,由此,枚举结果(只有三种结果),然后推到输入所给当前那轮,即可判断输入是否为可行解。若可行,对于一个正确解,同样可以用递推的方式,记 d p [ i ] : 0 dp[i]:0 dp[i]:0 为结果为布的字典序最小的解, 1 1 1 为石头, 2 2 2 为剪刀,所以对于下一轮的 d p dp dp 数组,可以通过当前轮的解推出。
#include <cstdio>
#include <iostream>
using namespace std;
#define ffor(i,d,u) for(int i=(d);i<=(u);++i)
#define _ffor(i,u,d) for(int i=(u);i>=(d);--i)
int r, p, s;
int total;
string str[3], mstr[3];//0:值为P(布),1:值为R(石头),2:值为S(剪刀)
int in[3][2] = {{0, 1}, {1, 2}, {2, 0}};
bool check(const int &ar, const int &ap, const int &as)
{
int mr, mp, ms;
mr = ar + ap, mp = ap + as, ms = as + ar;
if ((mr + mp + ms) == total)
return (mr == r && mp == p && ms == s);
return check(mr, mp, ms);
}
void print(int length)
{
if (length == total)
return;
mstr[0] = str[0], mstr[1] = str[1], mstr[2] = str[2];
ffor(i, 0, 2)
if (mstr[in[i][0]] > mstr[in[i][1]])
str[i] = mstr[in[i][1]] + mstr[in[i][0]];
else
str[i] = mstr[in[i][0]] + mstr[in[i][1]];
print(length << 1);
}
inline void AC()
{
cin >> r >> p >> s;
total = r + p + s;
str[0] = "PR", str[1] = "RS", str[2] = "PS";
print(2);
int ar, ap, as;
ar = 1, ap = 0, as = 0;
if (check(ar, ap, as))
{
cout << str[1];
return;
}
else
{
ar = 0, ap = 1, as = 0;
if (check(ar, ap, as))
{
cout << str[0];
return;
}
else
{
ar = 0, ap = 0, as = 1;
if (check(ar, ap, as))
{
cout << str[2];
return;
}
else
puts("IMPOSSIBLE");
}
}
}
int main()
{
AC();
return 0;
}