【搜索/tarjan找環】zznu-簡單環路


     簡單環路

題目描述

有一個N x M 大小的地圖,地圖中的每個單元包含一個大寫字母。
若兩個相鄰的(這里的相鄰指“上下左右”相鄰)點上的字母相同,我們可以用線段連接這兩個點。
若存在一個包含同一字母的環路,那么連接這些點我們可以得到一個多邊形,
當且僅當多邊形的邊數大於等於4時,我們稱這幅地圖中存在“簡單環路”。
現在給你一份地圖,你來判斷是否存在“簡單環路”。
列如:
3 4
AAAA
ABCA
AAAA
字符“A”可以構成一個“簡單環路”,其邊數為4。

輸入

第一行輸入兩個正整數n,m,2<=n,m<=50,分別表示地圖的行列數。
接下來輸入n行,每行m個大寫字母。

輸出

若存在“簡單環路”輸出“Yes”,否則輸出“No”。

樣例輸入

復制
3 4
AAAA
ABCA
AADA

樣例輸出

復制
No

 

大致分析:

  要想存在一個多邊形,至少需要四條邊,因為只能上下左右移動。

  方法1:重新構圖——把每個字母當成一個點,判斷上下左右如果有相同的則連上一條邊。用tarjan算法來進行判環,若遇見連接到更小的搜索序號dfn[]時,則可以認為這時找到了一個環,然后把這個環彈出來,數數長度(看是否滿足要求),再逆序放回去。

     方法2:據說搜索就可以了,只有相同字符之間的才可以進行搜索;后台數據比較弱,我用錯誤的代碼都過了。

 


 

答案:

  

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include<math.h>
#include <string.h>
#include<set>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 10000000
const double pi=acos(-1.0);
#define ll long long
#define N 55
#define M 50*50+5
char a[55][55];
vector<int>G[M];//表示每個點的周圍四個點的情況
int low_link[M],dfn[M],inst[M];
int Time;
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0} };
int n,m;
bool flag;
stack<int>st;
void judge(int i,int j,int num){
    for(int k=0;k<=3;k++){
        int dx=i+dir[k][0];
        int dy=j+dir[k][1];
        if(dx>=0&&dx<=n-1&&dy>=0&&dy<=m-1&&a[dx][dy]==a[i][j]){
            G[num].push_back(dx*m+dy);
        }
    }
}
void init(){
   Time=0;
   flag=false;
   for(int i=0;i<=n*m;i++)
        G[i].clear();
   memset(low_link,0,sizeof(low_link));
   memset(dfn,0,sizeof(dfn));
   memset(inst,0,sizeof(inst));
   while(!st.empty())
    st.pop();
}
void tarjan(int u,int fa){
    low_link[u]=dfn[u]=++Time;
    st.push(u);
    inst[u]=1;
    for(int i=0;i<(int)G[u].size();i++){
        int v=G[u][i];
        if(!dfn[v]){
            tarjan(v,u);
            low_link[u]=min(low_link[u],low_link[v]);
        }
        else if(inst[v]==1&&v!=fa){
            low_link[u]=min(low_link[u],dfn[v]);
            stack<int>q;
            int cnt=1;
            while(st.top()!=v){
                q.push(st.top());
                st.pop();
                cnt++;
            }
            if(cnt>=4){
                flag=true;
                   // printf("u=%d v=%d\n",u,v);
            }
            while(q.size()>0){
                st.push(q.top());q.pop();
            }
        }
    }

    if(low_link[u]==dfn[u]){
        while(st.top()!=u){
          //  printf("u=%d %d\n",u,st.top());
            inst[st.top()]=0;st.pop();
        }
        inst[st.top()]=0;st.pop();

    }

}
void debug(){
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            int num=i*m+j;
            for(int v=0;v<G[num].size();v++){
                printf("%d:%d ",num,G[num][v]);
            }
            cout<<endl;
        }
    }
}
int main(){

    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        for(int i=0;i<n;i++)
            scanf("%s",a[i]);
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                int num=i*m+j;
                judge(i,j,num);
            }
        }
     //   debug();
        for(int i=0;!flag&&i<n;i++){
            for(int j=0;!flag&&j<m;j++){
                int num=i*m+j;
                if(!dfn[num]){
                    tarjan(num,-1);
                     //if(flag==true)
                      //  printf("Yes num=%d\n",num);
                }
            }
        }
        if(flag==true)
            printf("Yes\n");
        else
            printf("No\n");
    }

    return 0;
}
View Code

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM