1. 程式人生 > >【51Nod - 1416】【兩點】

【51Nod - 1416】【兩點】

題目:

福克斯在玩一款手機解迷遊戲,這個遊戲叫做”兩點”。基礎級別的時候是在一個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;
}