zoukankan      html  css  js  c++  java
  • 51nod1416两点(dfs或并查集)

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

    1,dfs的思路就是暴力搜索,不往回搜(这步很重要),如果搜索的点标记过则有环,输出Yes,否则输出No
    代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    char s[55][55];
    int visit[55][55];
    int dir[4][2]={-1,0, 1,0, 0,-1, 0,1};
    int n,m,flag;
    void dfs(int x,int y,int sum,char ch)//x,y为坐标,ch是要搜索的字符,sum是搜索方向,0是上,1是下,2是左,3是右 
    {
        if(x<0||x>n||y<0||y>m||ch!=s[x][y])//越界和不符合条件 
            return ;
        if(visit[x][y]==1)//搜索终点,找到之前搜索过的 
        {
            flag=1;
            return ;
        }
        if(flag)
            return;
        visit[x][y]=1;
        for(int i=0;i<4;i++)
        {
            if(sum==0&&i==1)    continue;//如果是从向上搜索过来的,就不往下搜索 
            if(sum==1&&i==0)    continue;//往下搜索过来的,不往上搜索 
            if(sum==2&&i==3)    continue;//往左搜索过来的,不往右搜索
            if(sum==3&&i==2)    continue;//往右搜索过来的,不往左搜索
            int dx=x+dir[i][0];
            int dy=y+dir[i][1];
            dfs(dx,dy,i,ch);
            
        }
    }
    int main()
    {
        while(cin>>n>>m)
        {
            flag=0;
            memset(visit,0,sizeof(visit));
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    cin>>s[i][j];
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    if(!visit[i][j])//搜索每一个字母 
                        dfs(i,j,-1,s[i][j]);
                }
            if(flag==1)
                cout<<"Yes"<<endl;
            else
                cout<<"No"<<endl;
        }
        return 0;
    } 

    2.并查集思路:往下,往右走,如果字母相同,则令成同一祖先。如果有环,就成了矩形,矩形是关于对角线对称的,往下的会使最后的顶点先变成祖先相等,之后往右则和最后顶点祖先相等,则标记,退出循环就好。

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int fa[3000];
    char s[60][60];
    int find(int x)//查询祖先 
    {
        if(fa[x]==x)
            return x;
        else
            return fa[x]=find(fa[x]);
    }
    bool unionn(int x,int y)//连通祖先 
    {
        x=find(x);
        y=find(y);
        if(x==y)
            return true;//祖先相等则返回正确 
        fa[x]=y;
        return false;
    }
    int main()
    {
        int n,m;
        while(cin>>n>>m)
        {
            bool flag=false;
            for(int i=0;i<=n*m;i++)//每个点按矩阵编号1到n*m 
                fa[i]=i;
            for(int i=0;i<n;i++)
                for(int j=0;j<m;j++)
                    cin>>s[i][j];
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++)
                {
                    if(i!=n-1&&s[i][j]==s[i+1][j]&&unionn(i*m+j,(i+1)*m+j))//往下走 
                        flag=!flag;
                    if(j!=m-1&&s[i][j]==s[i][j+1]&&unionn(i*m+j,i*m+j+1))//往右走,碰到祖先相等则有环 
                        flag=!flag;
                    if(flag)
                        break;
                }
                if(flag)
                    break;
            }
            if(flag)
                cout<<"Yes"<<endl;
            else
                cout<<"No"<<endl;
        } 
        return 0;
    } 
  • 相关阅读:
    【总结+计划】七八月份总结+九月份计划——未知的状态最可怕
    【总结+计划】六月份总结+七月份计划——实习 就业 自学
    【计划】六月自学计划
    【总结】五月份总结——到底前端还是后台好呢
    Android中如何让DialogFragment全屏
    有用的
    Android Studio多渠道打包的使用
    adb not responding的解决方案
    ButterKnife的使用
    程序中判断android系统版本
  • 原文地址:https://www.cnblogs.com/xiongtao/p/9290328.html
Copyright © 2011-2022 走看看