【51Nod - 1416】【两点】

版权声明:本人原创,未经许可,不得转载 https://blog.csdn.net/qq_42505741/article/details/83116002

题目:

福克斯在玩一款手机解迷游戏,这个游戏叫做”两点”。基础级别的时候是在一个n×m单元上玩的。像这样:

 
 
 

每一个单元有包含一个有色点。我们将用不同的大写字母来表示不同的颜色。

这个游戏的关键是要找出一个包含同一颜色的环。看上图中4个蓝点,形成了一个环。一般的,我们将一个序列 d1,d2,...,dk 看成一个环,当且仅当它符合下列条件时:

1.    这k个点不一样,即当 i≠j时, di 和 dj不同。

2.    k至少是4。

3.    所有的点是同一种颜色。

4.    对于所有的 1≤i≤k-1: di 和 di+1 是相邻的。还有 dk 和 d1 也应该相邻。单元 x 和单元 y 是相邻的当且仅当他们有公共边。

当给出一幅格点时,请确定里面是否有环。

Input

单组测试数据。 
第一行包含两个整数n和m (2≤n,m≤50):板子的行和列。 
接下来n行,每行包含一个有m个字母的串,表示当前行每一个点的颜色。每一个字母都是大写字母。

Output

如果有环输出Yes,否则输出No。

Sample Input

3 4
AAAA
ABCA
AAAA
3 4
AAAA
ABCA
AADA

Sample Output

Yes
No

解题报告:很明确是图的题目,叫我们输入后进行判断是否存在由字母组成的环,原本打算用搜索,发现不现实,因为字母的种类有太多了,然后,自然想到并查集,将每两个相邻的点merge连起来,如果遇到两个点已经是在一个集合里的时候,就可以跳出来,说明是有环存在的。如果没有就一直进行下去。中间需要注意的转换思维的一点就是咱们将二维的图转换成了一维的far数组,所以行数*m  = =。

ac代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
using namespace std;

const int maxn = 2510;
int n,m;
int far[maxn];
char str[maxn][maxn];
int ety(int a,int b)
{
	return a*m+b;
}
int find(int x)
{
	if(x!=far[x])
		return far[x]=find(far[x]);
	return far[x];
}
int merge(int a,int b)
{
	int pa=find(a);
	int pb=find(b);
	if(pa==pb)
		return 0;
	far[pa]=far[pb]=min(pa,pb);
	return 1;
}
void init()
{
	for(int i=0;i<=n*m;i++)
		far[i]=i;
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(str,0,sizeof(str));
		init();
		for(int i=0;i<n;i++)
			scanf("%s",str[i]);
		int ok=1;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(i!=n-1&&str[i][j]==str[i+1][j])
					ok=merge(ety(i,j),ety(i+1,j));
				if(!ok)
					break;
				if(j!=m-1&&str[i][j]==str[i][j+1])
					ok=merge(ety(i,j),ety(i,j+1));
				if(!ok)
					break;
			}
			if(!ok)
				break;
		}
		if(ok) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42505741/article/details/83116002
今日推荐