Problem E. Epic Win!


题目描述:

Problem E. Epic Win!
Input file: epic.in
Output file: epic.out
A game of rock-paper-scissors is played by two players who simultaneously show out their moves: Rock,
Paper , or Scissors. If their moves are the same, it’s a draw. Otherwise, Rock beats Scissors, Paper beats
Rock, and Scissors beat Paper .
The described procedure can be repeated many times. In this problem, two Finite State Machines
(FSMs) will compete in a series of rounds. (Formally speaking, by FSMs we mean Moore machines in
this problem.)
An FSM for playing rock-paper-scissors has finitely many states. Each state is described by the following:
what move the FSM will make in the upcoming round, and what will be the new state in case of its
opponent playing Rock, Paper , and Scissors.
play R play P
S
S
R, P R, P play P play S
start
P
R, P, S
R, S
Fortunately, you know your opponent FSM — the entire scheme except for one thing: you do not know
the initial state of that FSM.
Your task is to design your own FSM to fight the given one. Your FSM must beat the opponent in at
least 99% of the first 1 billion rounds. That’s what we call an epic win!
Input
The input file contains a description of the opponent FSM in the following format.
The first line contains an integer n (1 ≤ n ≤ 100) — the number of states in the FSM. States are
numbered from 1 to n. Each of the following n lines contains a description of the state: a character ci
denoting the move made by FSM and integers ri
, pi
, si denoting the next state in case of seeing Rock,
Paper , or Scissors respectively (ci can be ”R”, ”P”, or ”S”; 1 ≤ ri
, pi
, si ≤ n).
Output
Write to the output the description of your FSM in the same format.
The initial state of your FSM is the first state.
The number of states may not exceed 50 000.
Sample input and output
epic.in epic.out
2
R 1 1 2
P 2 2 1
2
P 1 2 1
S 1 1 1
The picture in the problem statement illustrates the opponent FSM given in the above sample input and
a possible solution of yours given in the sample output.
Opponent FSM keeps playing Rock or Paper (depending on its initial state) until it sees Scissors —
seeing Scissors triggers a change in its behaviour.
One way to beat such FSM is to play Paper . If your opponent keeps playing Rock, just continue playing
Paper and thus win. If the opponent FSM is playing Paper , trigger it to playing Rock by playing Scissors
once, and then it’ll keep playing Rock and you’ll keep beating it with your Paper .

题解:

首先很容易想到对于对手的第一个点怎么办: 根据它的情况每次我自己的点建一个赢他的点,然后往下跑,直到对手的自动机跑到了一个已经vis过的点,那么我就直接指向那个点就好了. 用vis来记录.设这个方法叫做getWin.
之后的点就是当时没想好的了.其实也很简单:我们枚举2…n, 对于开始的点i,两边同时跑,如果跑出来了一个以前没有的边(点),那么我们可以以后开始自己新的构建,利用getWin的方法. 但是如果一直没有跑出来新的点呢?我们发现我建立的是一个必胜自动机,pos(对手状态号),now(我的状态号)的情况下,我是赢的,而下一次转移也转移到了一个pos和now,那么我也是赢的. 判断循环的产生是用have[pos][now]来打标记.

重点:

关于之后点循环的时候会赢的想法.我的自动机可以是一个必胜自动机.只要一直沿着我跑,那么当前的都是赢的,按照我的预测的话是赢得,不按照我的预测的话,那么就会能够建新边.

代码:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 10000+100;
int op[maxn][100];
int my[maxn][100];
int tot, vis[100+10];
int have[100+10][10000+100];
int n;

int win(int ch)
{
    if(ch == 'S')
        return 'R';
    else if(ch == 'R')
        return 'P';
    else
        return 'S';
}

void getWin(int pos, int lastS, int lastB)/  my  memset 0000
{
    //printf("pos ***  %d  %d  %d\n", pos, lastS, lastB);
    memset(vis, 0, sizeof(vis));
    while(vis[pos]==0)
    {
        ++tot;
        if(lastS != -1)
            my[lastS][lastB] = tot;
        vis[pos] = tot;
        my[tot][0] = win(op[pos][0]);
        //printf("***** %d tot is %d\n", my[tot][0], tot);
        lastS = tot;
        lastB = op[pos][0];
        pos = op[pos][my[tot][0]];
    }
    //printf("lastS %d lastB  %d\n", lastS, lastB);
    my[lastS][lastB] = vis[pos];
    //printf("hou***** %d tot is %d\n", my[1][0], 1);
}

void solve()
{
    memset(have, 0, sizeof(have));
    memset(my, 0, sizeof(my));
    int now = 1, pos, lastS, lastB;
    tot = 0;
    for(int i = 1; i<=n; i++)
    {
        lastS = -1;
        lastB = -1;
        if(i != 1)
            now = 1;
        else
            now = 0;
        pos = i;
        while(now != 0 && have[pos][now]!=i)
        {
            have[pos][now] = i;
            int tmpnow = now;
            lastS = tmpnow;
            lastB = op[pos][0];
            now = my[now][op[pos][0]];
            pos = op[pos][my[tmpnow][0]];
        }
        if(now != 0)
        {
            continue;
        }
        getWin(pos, lastS, lastB);
        //printf("***** %d tot is %d\n", my[1][0], 1);
    }
    printf("%d\n", tot);
    for(int i = 1; i<=tot; i++)
    {
        printf("%c", my[i][0]);
        int t = my[i]['R'];
        if(t == 0)
            t = 1;
        printf(" %d", t);

        t = my[i]['P'];
        if(t == 0)
            t = 1;
        printf(" %d", t);

        t = my[i]['S'];
        if(t == 0)
            t = 1;
        printf(" %d", t);
        printf("\n");
    }
}

int main()
{
    //printf("%d %d %d\n", 'R', 'P', 'S');
    freopen("epic.in", "r", stdin);
    freopen("epic.out", "w", stdout);
    while(scanf("%d", &n) != EOF)
    {
        for(int i = 1; i<=n; i++)
        {
            char ch[10];
            int  a, b, c;
            scanf("%s%d%d%d", ch, &a, &b, &c);
            op[i][0] = ch[0];
            //printf("op is %d\n", op[i][0]);
            op[i]['R'] = a;
            op[i]['P'] = b;
            op[i]['S'] = c;
        }
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值