簡單環路
題目描述
有一個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; }