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;
}

浙公网安备 33010602011771号