题目描述
有一个N x M 大小的地图,地图中的每个单元包含一个大写字母。
若两个相邻的(这里的相邻指“上下左右”相邻)点上的字母相同,我们可以用线段连接这两个点。
若存在一个包含同一字母的环路,那么连接这些点我们可以得到一个多边形,
当且仅当多边形的边数大于等于4时,我们称这幅地图中存在“简单环路”。
现在给你一份地图,你来判断是否存在“简单环路”。
列如:
3 4
AAAA
ABCA
AAAA
字符“A”可以构成一个“简单环路”,其边数为4。
输入
第一行输入两个正整数n,m,2<=n,m<=50,分别表示地图的行列数。
接下来输入n行,每行m个大写字母。
输出
若存在“简单环路”输出“Yes”,否则输出“No”。
样例输入
3 4
AAAA
ABCA
AADA
样例输出
No
思路
并查集,把每个相同的点合成一个祖先。如果遇到两个点相同,而且他们的祖先也相同,那么就形成环了。
AC
#include<bits/stdc++.h>
#define ll long long
#define mem(a, b) memset(a, b, sizeof(a))
#define N 105
using namespace std;
char g[N][N];
int n, m;
int pre[N * N];
// 获取每个坐标的唯一id
int id(int i, int j) {
return i * m + j;
}
//祖先初始化
void init() {
for (int i = 0; i < N * N; i++) {
pre[i] = i;
}
}
// 查找祖先
int find (int x) {
if (x == pre[x]) return x;
else return pre[x] = find(pre[x]);
}
int main() {
// freopen("in.txt", "r", stdin);
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%s", &g[i]);
}
init();
int flag = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
//左右方向
if (g[i][j] == g[i][j + 1]) {
int u = id(i, j);
int v = id(i, j + 1);
int find_u = find(u);
int find_v = find(v);
if (find_u != find_v) {
pre[find_u] = pre[find_v];
find(find_u);
}else {
flag = 1;
break;
}
}
//上下方向
if (g[i][j] == g[i + 1][j]) {
int u = id(i, j);
int v = id(i + 1, j);
int find_u = find(u);
int find_v = find(v);
if (find_u != find_v) {
pre[find_u] = pre[find_v];
find(find_u);
}else {
flag = 1;
break;
}
}
}
if (flag) break;
}
if (flag) printf("Yes\n");
else printf("No\n");
}
return 0;
}