题解:P16183 [ICPC 2014 NAIPC] Two Knight' s Poem

P16183 题解

题目

这道题的核心是判断两位国际象棋骑士能否在特制键盘上合作“走”出一首给定的诗

具体规则如下:

  1. 棋盘与棋子:键盘是一个 \(4\)\(10\)的网格。两位骑士分别从最左边最右边的 Shift 键出发。骑士只能按象棋中“日字步”移动,且不能同时占据同一个按键

  2. 按键与输入规则

    • 落在符号键上会输入字符。若另一位骑士恰好站在某个 Shift 键上,则输入该键的上档字符(如大写字母);否则输入下档字符(如小写字母)。
    • 落在空格键上始终输入空格(与 Shift 状态无关)。
    • 落在 Shift 键不输入任何字符(仅作为中转站,用于改变另一位骑士的 Shift 状态)。
  3. 行动顺序:两位骑士可以任意轮流移动,甚至同一位骑士可以连续移动多次。每次移动最多输入一个字符(落在符号或空格上时)。

  4. 任务与输出:给定一首长度 \(1\)\(100\) 的诗(仅含键盘符号和空格,不以空格开头结尾),判断骑士们能否通过一系列合法移动,依次精确地输入这首诗的每个字符。能则输出 1,否则输出 0。输入包含多组测试用例,以 * 结束。

做法

考虑设计状态 \(f_{{step},{pos_1},{pos_2}}\) 代表要匹配 \(s\) 的第 \(step\) 位的时候左边的骑士在 \(pos_1\) 的位置,右边的骑士在 \(pos_2\) 的位置可不可做到。

考虑使用 DFS。以左边的为例,遍历所有可以到的地方 \(npos\)。如果 \(npos\) 是 Shift,那么 \(f_{step,npos,pos_2}\) 也为真,继续递归。如果是 \(s_{step}\) 那么 \(f_{step+1,npos,pos_2}\) 也为真。之后继续递归即可。

如果新状态原本也为真,说明已经有分支递归过了,就不递归。

如果 \(step=n\),说明已经全部匹配完成,直接回溯即可。

由于每一个状态只会递归一次,所以复杂度是和状态数成线性关系,总状态数和总字符串大小也成线性关系,且输入大约 12KB,大约 \(1.3\times10^4\),不会 TLE。

代码

#include <bits/stdc++.h>
using namespace std;
bool vis[105][4][10][4][10];
const int DIR[8][2] = {
    {1, 2}, {-1, 2}, {1, -2}, {-1, -2},
    {2, 1}, {2, -1}, {-2, 1}, {-2, -1}
};
const char kbroad[2][4][11] = {
    {"qwertyuiop", "asdfghjkl;", "zxcvbnm,./", "@@      @@"},
    {"QWERTYUIOP", "ASDFGHJKL:", "ZXCVBNM<>?", "@@      @@"}
};
int n, flg = 0;
string s;
void dfs(int step, int lx, int ly, int rx, int ry) {
    if(step == n) flg = 1;
    if(flg) return;
    vis[step][lx][ly][rx][ry] = 1;
    for(auto [dx, dy] : DIR) {
        int nx = lx + dx, ny = ly + dy;
        if(nx < 0 || nx > 3 || ny < 0 || ny > 9 || (nx == rx && ny == ry))
            continue;
        auto nk = kbroad[kbroad[0][rx][ry] == '@'][nx][ny];
        if(nk == '@' && !vis[step][nx][ny][rx][ry])
            dfs(step, nx, ny, rx, ry);
        if(nk == s[step] && !vis[step + 1][nx][ny][rx][ry])
            dfs(step + 1, nx, ny, rx, ry);
        if(flg) return;
    }
    for(auto [dx, dy] : DIR) {
        int nx = rx + dx, ny = ry + dy;
        if(nx < 0 || nx > 3 || ny < 0 || ny > 9 || (nx == lx && ny == ly))
            continue;
        auto nk = kbroad[kbroad[0][lx][ly] == '@'][nx][ny];
        if(nk == '@' && !vis[step][lx][ly][nx][ny])
            dfs(step, lx, ly, nx, ny);
        if(nk == s[step] && !vis[step + 1][lx][ly][nx][ny])
            dfs(step + 1, lx, ly, nx, ny);
        if(flg) return;
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(0);
    while(getline(cin, s)) {
        if(s == "*") break;
        s.pop_back();//去除\r
        n = s.size();
        for(int i = 0; i <= n; i++)
            memset(vis[i], 0, sizeof(vis[i]));
        flg = 0;
        dfs(0, 3, 0, 3, 9);
        cout << flg << "\n";
    }
}

题意部分使用了 DeepSeek V4 Flash 进行总结。

posted @ 2026-09-02 11:02  Monotonic_Deque  阅读(4)  评论(0)    收藏  举报