CF382D Ksenia and Pawns 题解

解题过程

题目中给定了格子的箭头,也就是这条路径已经确定了。那么我们就可以选择任意一个位置为起点,按照格子上的方向模拟走路的过程。

什么时候答案会无穷大呢?仔细思考不难发现,如果图上出现了环(如图所示),那么两个士兵就可以沿着这个环无限的走下去,对于图上出现环的情况,应当输出 \(-1\)

接下来考虑如何模拟,对于每一条不同的路径,我们要对这条路径打上不同的标记:历史上走过的标记 \(his\) 和当前路径上的标记 \(vis\),以及染上不同的颜色,以及用栈记录下走过的节点。其中 \(his\) 的作用是避免重复走走过的路径,\(vis\) 的作用是判断图上是否有环,染色的目的是区分不同的路。用栈记录下节点后,原路返回,给每个经过的节点染色并求出这条路的距离。

最后考虑答案,对于有解的情况下,如果只存在一条路,格子数为 \(n\),显然,答案应为 \(2n - 1\)。(如图所示)

在有多条路的情况下,我们需要选择尽可能长的路。当存在多条最长路,格子数为 \(n\) 时,答案为 \(2n\),否则必然选择那唯一一条路,答案为 \(2n-1\)

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
bitset <N> vis[N], his[N];//此处用bitset优化,也可以开bool数组
int tot, col[N][N], dis[N][N], n, m;
char mp[N][N];
stack <pair <int, int> > stk;
int main () {
    ios :: sync_with_stdio (0);
    cin.tie (0), cout.tie (0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> mp[i][j];
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++)  {
            if (mp[i][j] == '#' || his[i][j]) continue;
            int x = i, y = j;
            while (!his[x][y]) {//历史上没有走过
            //模拟
                stk.push ({x, y});
                his[x][y] = vis[x][y] = 1;
                if (mp[x][y] == '^') x--;
                else if (mp[x][y] == 'v') x++;
                else if (mp[x][y] == '<') y--;
                else if (mp[x][y] == '>') y++;
                else {
                    stk.pop (), his[x][y] = vis[x][y] = 0;
                    x = stk.top ().first;
                    y = stk.top ().second;
                    stk.pop (), vis[x][y] = 0;
                    dis[x][y] = 1, col[x][y] = ++tot;
                    break;
                }
            }
            if (vis[x][y]) return cout << -1, 0;//形成环了
            while (!stk.empty ()) {//回退并记录
                int px = stk.top ().first;
                int py = stk.top ().second;
                stk.pop ();
                vis[px][py] = 0;
                dis[px][py] = dis[x][y] + 1, col[px][py] = col[x][y];
                x = px, y = py;
            }
        }
    }
    int x = 0, y = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (dis[i][j] > dis[x][y])
                x = i, y = j;//寻找最长路
    if (x == 0 && y == 0) return cout << 0, 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (dis[i][j] == dis[x][y] && col[i][j] != col[x][y])
                return cout << dis[x][y] * 2, 0;
    return cout << dis[x][y] * 2 - 1, 0;
}
posted @ 2025-12-20 14:26  暴力算法  阅读(0)  评论(0)    收藏  举报