牛客寒假算法基础集训营6 - F 石头剪刀布 构造

题目链接

题意:一共三种人,喜欢石头、剪刀、布,设定为喜欢石头的和喜欢剪刀的玩,喜欢石头的赢,以此类推。设一共 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值