您的位置:首页 > 其它

51nod 1416 两点【并查集】

2016-12-08 15:15 274 查看
1416 两点

题目来源: CodeForces

基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题

福克斯在玩一款手机解迷游戏,这个游戏叫做”两点”。基础级别的时候是在一个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。


Input示例
3 4
AAAA
ABCA
AAAA
3 4
AAAA
ABCA
AADA


Output示例
Yes
No


思路(每日第一水~):

我们首先对每种颜色(字母)的图进行建立,对应我们建立无向图,将建好的图存入vector<>中,然后我们用并查集暴力判断是否存在无向图即可。

Ac代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
vector<int >mp[500000];
int f[500000];
char a[120][120];
int vis[2501][2501];
int fx[5]={0,0,1,-1};
int fy[5]={1,-1,0,0};
int find(int a)
{
int r=a;
while(f[r]!=r)
r=f[r];
int i=a;
int j;
while(i!=r)
{
j=f[i];
f[i]=r;
i=j;
}
return r;
}
void merge(int a,int b)
{
int A,B;
A=find(a);
B=find(b);
if(A!=B)
f[B]=A;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<n;i++)
{
scanf("%s",a[i]);
}
int flag=0;
for(int i=0;i<26;i++)
{
memset(vis,0,sizeof(vis));
for(int j=0;j<=n*m+1;j++)mp[j].clear(),f[j]=j;
for(int j=0;j<n;j++)
{
for(int k=0;k<m;k++)
{
if(a[j][k]-'A'==i)
{
for(int z=0;z<4;z++)
{
int xx=fx[z]+j;
int yy=fy[z]+k;
if(xx>=0&&xx<n&&yy>=0&&yy<m&&a[xx][yy]-'A'==i)
{
int u=j*m+k+1;
int v=xx*m+yy+1;
if(vis[u][v]==0)
{
mp[u].push_back(v);
vis[u][v]=1;
vis[v][u]=1;
}
}
}
}
}
}
for(int j=1;j<=n*m;j++)
{
for(int k=0;k<mp[j].size();k++)
{
if(find(j)==find(mp[j][k]))
{
flag=1;
}
else merge(j,mp[j][k]);
}
}
if(flag==1)break;
}
if(flag==1)printf("YES\n");
else printf("NO\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  51nod 1416