标签: 模拟

[CF3C]Tic-tac-toe 题解

[CF3C]Tic-tac-toe 题解

题目地址:Codeforces:Problem – 3C – Codeforces、洛谷:CF3C Tic-tac-toe – 洛谷 | 计算机科学教育新生态

题目描述

Certainly, everyone is familiar with tic-tac-toe game. The rules are very simple indeed. Two players take turns marking the cells in a 3 × 3 grid (one player always draws crosses, the other — noughts). The player who succeeds first in placing three of his marks in a horizontal, vertical or diagonal line wins, and the game is finished. The player who draws crosses goes first. If the grid is filled, but neither Xs, nor 0s form the required line, a draw is announced.

You are given a 3 × 3 grid, each grid cell is empty, or occupied by a cross or a nought. You have to find the player (first or second), whose turn is next, or print one of the verdicts below:

  • illegal — if the given board layout can’t appear during a valid game;
  • the first player won — if in the given board layout the first player has just won;
  • the second player won — if in the given board layout the second player has just won;
  • draw — if the given board layout has just let to a draw.

题意简述

给一个井字棋(三子棋)的局面,请判断该局面的状态,状态有以下几种:

  • 下一步X玩家下棋
  • 下一步O玩家下棋
  • 非法状态(正常游戏过程中不会出现的局面)
  • X玩家获胜
  • O玩家获胜
  • 平局

井字棋玩法请百度。

输入输出格式

输入格式:
The input consists of three lines, each of the lines contains characters “.”, “X” or “0” (a period, a capital letter X, or a digit zero).

输出格式:
Print one of the six verdicts: first, second, illegal, the first player won, the second player won or draw.

输入输出样例

输入样例#1:

X0X
.0.
.X.

输出样例#1:

second

题解

大模拟题,细节和分类特别多。分状态讨论符合的情况。

下一步X下棋,仅出现于合法且无人获胜的局面中,特征是局面中X和O的数量相同。
下一步O下棋,仅出现于合法且无人获胜的局面中,特征是局面中X比O的数量多1。
非法状态,有以下几类:X与O的数量的关系既不是相同也不是X比O多1;X获胜之后O仍然下了一步棋(X获胜之后X与O数量相同);O获胜之后X仍然下了一步棋(O获胜之后X比O数量多1)。
X获胜,合法局面中X棋子占据了某一行、列或正副对角线。
O获胜,合法局面中O棋子占据了某一行、列或正副对角线。
平局,合法局面,无人获胜,且棋盘中没有空位。

调试的时候平均一个submission过一个测试点,果然还是我太菜了。

代码

// Code by KSkun, 2019/6
#include <cstdio>

char a[5][5];

int main() {
    scanf("%s%s%s", a[1] + 1, a[2] + 1, a[3] + 1);
    int cntx = 0, cnto = 0;
    bool hasdot = false;
    for(int i = 1; i <= 3; i++) {
        for(int j = 1; j <= 3; j++) {
            if(a[i][j] == 'X') cntx++;
            if(a[i][j] == '0') cnto++;
            if(a[i][j] == '.') hasdot = true;
        }
    }
    if(cntx != cnto && cntx != cnto + 1) {
        puts("illegal"); return 0;
    }
    bool fw = false, sw = false;
    for(int i = 1; i <= 3; i++) {
        if(a[i][1] == a[i][2] && a[i][2] == a[i][3]) {
            if(a[i][1] == 'X') fw = true;
            else if(a[i][1] == '0') sw = true;
        }
    }
    for(int i = 1; i <= 3; i++) {
        if(a[1][i] == a[2][i] && a[2][i] == a[3][i]) {
            if(a[1][i] == 'X') fw = true;
            else if(a[1][i] == '0') sw = true;
        }
    }
    if(a[1][1] == a[2][2] && a[2][2] == a[3][3]) {
        if(a[1][1] == 'X') fw = true;
        else if(a[1][1] == '0') sw = true;
    }
    if(a[1][3] == a[2][2] && a[2][2] == a[3][1]) {
        if(a[1][3] == 'X') fw = true;
        else if(a[1][3] == '0') sw = true;
    }
    if(fw && sw) puts("illegal");
    else if(fw && cntx != cnto + 1) puts("illegal");
    else if(sw && cntx != cnto) puts("illegal");
    else if(fw) puts("the first player won");
    else if(sw) puts("the second player won");
    else if(!hasdot) puts("draw");
    else if(cntx == cnto) puts("first");
    else if(cntx == cnto + 1) puts("second");
    return 0;
}
[工程师死绝的世界B2003]隔離された街のゲート 翻译及题解

[工程师死绝的世界B2003]隔離された街のゲート 翻译及题解

被隔离的街道的大门

Translation by KSkun

原题:問題「隔離された街のゲート」 | エンジニアが死滅シタ世界 〜アンドロイドとふたりぼっちで生きろ〜

问题描述

你找到了一个未完成的游戏程序,这个游戏没有实现控制角色移动的方法。

这个未完成的游戏使用宽为 W 高为 H 的网格图作为地图。
左下角的点是原点,坐标是 (0, 0) 。
从原点横向前进 x 单位,纵向前进 y 单位到达的点坐标表示为 (x, y) 。

现在由于处于开发阶段,地图上没有障碍物,角色的初始坐标为 (0, 0) 。
从该状态开始,执行总共 N 个的向上、下、左或右的移动操作。
各个移动操作对角色坐标 (x, y) 的更改情况如下所示:

  • 向上移动:将角色的坐标从 (x, y) 变为 (x, y + 1) 。
  • 向下移动:将角色的坐标从 (x, y) 变为 (x, y – 1) 。
  • 向左移动:将角色的坐标从 (x, y) 变为 (x – 1, y) 。
  • 向右移动:将角色的坐标从 (x, y) 变为 (x + 1, y) 。

在开发需求文档中,需要编写一个能够判断角色在 N 次移动操作的过程中是否处于不合法的坐标上。
这里的不合法的坐标指的是在地图之外的坐标,也就是地图上不存在的坐标。
例如,输入输出样例1和2可以表示如下。

botchi b 2003 img1 - [工程师死绝的世界B2003]隔離された街のゲート 翻译及题解

botchi b 2003 img2 - [工程师死绝的世界B2003]隔離された街のゲート 翻译及题解

输入格式

H W N 
d_1 
... 
d_N
  • 第一行包含三个整数,分别是地图的高 H 、宽 W 和移动操作的次数 N ,数值之间用一个半角空格分隔。
  • 接下来的 N 行,第 i (1 ≦ i ≦ N) 行包含一个字符,代表第 i 次移动操作的方向。”U“代表向上,”D“代表向下,”L“代表向左,”R“代表向右。
  • 输入数据一共包含 N + 1 行,输入的的末尾包含一个空行。

输出格式

在 N 次移动操作中,如果角色到达了不合法的坐标,则输出一行“invalid”,否则输出一行“valid”。

条件

  • 1 ≦ H, W ≦ 50
  • 1 ≦ N ≦ 500
  • 对于任意 i (1 ≦ i ≦ N) , d_i 的值为大写英文字母”U”、”D”、”L”、”R”中的一个。

输入输出样例

输入输出样例1

输入:

3 3 5 
U 
R 
D 
R 
L

输出:

valid

输入输出样例2

输入:

4 4 7 
U 
U 
R 
R 
R 
R 
D

输出:

invalid

题解

// Code by KSkun, 2019/5
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
        ? EOF : *p1++;
}

inline LL readint() {
    LL res = 0, neg = 1; char c = fgc();
    for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
    for(; isdigit(c); c = fgc()) res = res * 10 + c - '0';
    return res * neg;
}

inline char readsingle() {
    char c;
    while(!isgraph(c = fgc())) {}
    return c;
}

inline bool isop(char c) {
    return c == 'U' || c == 'D' || c == 'R' || c == 'L';
}

inline char readop() {
    char c;
    while(!isop(c = fgc())) {}
    return c;
}

int n, m, N;

int main() {
    n = readint(); m = readint(); N = readint();
    int nx = 0, ny = 0;
    while(N--) {
        char op = readop();
        if(op == 'U') ny++;
        else if(op == 'D') ny--;
        else if(op == 'L') nx--;
        else if(op == 'R') nx++;
        if(nx < 0 || nx >= n || ny < 0 || ny >= m) {
            puts("invalid"); 
            return 0;
        }
    }
    puts("valid");
    return 0;
}
[工程师死绝的世界C3003]学べない学校 翻译及题解

[工程师死绝的世界C3003]学べない学校 翻译及题解

没有学生的学校

Translation by KSkun

原题:問題「学べない学校」 | エンジニアが死滅シタ世界 〜アンドロイドとふたりぼっちで生きろ〜

问题描述

学校里的孩子们在玩剪刀石头布。特别是A君和B君,每天都要来上几盘,两人争来争去非要比个高下。
你知道了两个人的游戏记录,他们想让你写一个程序来判定他们谁最强。
A君和B君一共进行了N次游戏。
你知道了他们进行的游戏次数N以及每一次的状况,你需要写一个统计A君和B君获胜次数的程序。

剪刀石头布有三种手势:剪刀、石头、步。
石头可以赢剪刀,剪刀赢布,布赢石头。

输入中:

  • 石头用g表示
  • 剪刀用c表示
  • 布用p表示

样例1的说明如下图所示。

botchi c 3003 img - [工程师死绝的世界C3003]学べない学校 翻译及题解

输入格式

N 
a_1 b_1 
a_2 b_2 
... 
a_N b_N
  • 第一行包含一个整数N,表示A君和B君游戏的次数。
  • 接下来的N行,每行包含两个用半角空格分开的字符a_i和b_i,分别代表A君和B君的出法(字符对应出法参见问题描述)。
  • 输入共N + 1行,在输入的最后,包含一个换行符。

输出格式

以以下的格式分别输出A君和B君获胜的次数。

w_a 
w_b
  • 输出应该包含2行。
  • 第一行输出一个整数w_a,表示A君获胜的次数。
  • 第二行输出一个整数w_b,表示B君获胜的次数。
  • 输出的最后应该包含一个换行符。

条件

  • 1 ≦ N ≦ 1000
  • a_i和b_i只可能是gcp中的一种。

输入输出样例

输入输出样例1

输入:

3 
g g 
c p 
p g

输出:

2 
0

输入输出样例2

输入:

10 
p g 
c c 
p p 
g g 
c p 
c p 
g g 
p p 
g p 
p g

输出:

4 
1

题解

// Code by KSkun, 2019/1
#include <cstdio>
#include <cctype>

#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
        ? EOF : *p1++;
}

inline LL readint() {
    LL res = 0, neg = 1; char c = fgc();
    for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
    for(; isdigit(c); c = fgc()) res = res * 10 + c - '0';
    return res * neg;
}

inline char readsingle() {
    char c;
    while(!isgraph(c = fgc())) {}
    return c;
}

inline int win(char a, char b) {
    if(a == b) return 0;
    if(a == 'g' && b == 'c') return 1;
    if(a == 'c' && b == 'p') return 1;
    if(a == 'p' && b == 'g') return 1;
    return -1;
}

int n, cnta = 0, cntb = 0;
char wa[5], wb[5];

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%s%s", wa, wb);
        int res = win(wa[0], wb[0]);
        if(res > 0) cnta++;
        else if(res < 0) cntb++;
    }
    printf("%d\n%d\n", cnta, cntb);
    return 0;
}