由于路径除起点外不能重复经过一点且需要回到起点,那么出发时和结束时一定会经过与起点 \(\text{S}\) 相邻的不同的点。如果存在两个这样的点联通,那么就存在这样一条从起点出发返回起点的回路。
但题目中有对路径长大于等于 \(4\) 的限制,可以发现走一个 \(2\times2\) 的矩阵回到原点是满足条件的最短可能路线,所以只要存在这样一条回路,其长度一定大于等于 \(4\)。
具体实现对每一个方格标号,使用路径压缩并查集维护点与点之间的连通性,最后判断是否存在与起点 \(\text{S}\) 相邻的两个点在同一个联通块中。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int SIZE = 1000005;
const int mod = 998244353;
const int X[5] = {0, -1, 0, 1, 0};
const int Y[5] = {0, 0, -1, 0, 1};
int n, m;
vector<char> mp[SIZE];
int fa[SIZE];
int siz[SIZE];
int sx, sy;
inline int rd(){
int f = 1, x = 0;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return f*x;
}
int get(int x){
if(fa[x] == x) return x;
return fa[x] = get(fa[x]);
}
int getid(int x, int y){
return (x-1)*m+y;
}
int main(){
n = rd(), m = rd();
for(int i = 1; i <= n; i++) mp[i].push_back('a');
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
char c; cin >> c;
mp[i].push_back(c);
fa[getid(i, j)] = getid(i, j);
siz[getid(i, j)] = 1;
if(c == 'S') sx = i, sy = j;
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(mp[i][j] != '.') continue;
for(int k = 1; k <= 4; k++){
int x = i + X[k], y = j + Y[k];
if(x <= 0 || y <= 0 || x > n || y > m || mp[x][y] != '.') continue;
int xx = get(getid(i, j)), yy = get(getid(x, y));
if(xx != yy) fa[xx] = yy, siz[yy] += siz[xx];
}
}
}
for(int i = 1; i <= 4; i++){
int x1 = sx + X[i];
int y1 = sy + Y[i];
if(x1 <= 0 || y1 <= 0 || x1 > n || y1 > m || mp[x1][y1] != '.') continue;
for(int j = i+1; j <= 4; j++){
int x2 = sx + X[j];
int y2 = sy + Y[j];
if(x2 <= 0 || y2 <= 0 || x2 > n || y2 > m || mp[x2][y2] != '.') continue;
int xx = get(getid(x1, y1)), yy = get(getid(x2, y2));
if(xx == yy){
printf("Yes\n");
return 0;
}
}
}
printf("No");
return 0;
}