51nod 1416 两点【并查集】

本文介绍了一款名为“两点”的解谜游戏算法题,玩家需要在一个n×m的单元格中找出相同颜色的环。文章详细解释了游戏规则,并提供了一个使用并查集算法的AC代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源:  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");
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值