题目链接:http://codeforces.com/problemset/problem/510/B
题目大意:找出一个相同字母的环,之前作比赛的时候就一直超时,写的挫的要死的dfs,今天又看到这题,又来做了下,还是运用dfs
思路:运用dfs进行查找,并将每个点进行标记,如果找到之前已经标记过的点,那么就说明了这个形成了一个环啊。但是这里有个问题就是,如果一个点进行深搜的时候找到了他的上一个点,这样的话因为上一个点肯定是标记过的,这样也就会直接被判断成环,但这明显不是的。所以在dfs的基础上要进行改进,加两个参数来记录上一个点,如果找的点与上一个点相同就跳过。
还有一个地方要注意的就是,找到目标后,就直接将标记变量更新为true,不要用返回值的方式,因为dfs是回溯的,返回值感觉不好写orzzzz,一开始就错在这里,直接运用一个变量就好了,不需要返回值。。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define M 59
char map[M][M];
bool vis[M][M];
int d1[4] = {1,-1,0,0};
int d2[4] = {0,0,1,-1};
int n,m;
struct state
{
int x,y;
}cur,next1;
bool ok;
void dfs(int x,int y,int fx,int fy,char c) //记录下该点的前一个点,防止之后直接走回之前的点而被判为yes
{
vis[x][y] = true;
for(int i = 0;i < 4;i++)
{
int nx = x+d1[i];
int ny = y+d2[i];
if(nx>=0&&nx<n&&ny>=0&&ny<m&&map[nx][ny]==c) //保证字符相同
{
if(nx==fx && ny==fy) continue; //走的下一个点不为当前点的上一个点。
if(vis[nx][ny])//如果这个点已被标记说明形成了一个环,找到。
{
ok = true;
return;
}
vis[nx][ny] = true;
dfs(nx,ny,x,y,c);
}
}
return ;
}
int main()
{
while(scanf("%d %d",&n,&m)==2)
{
memset(vis,false,sizeof(vis));
getchar();
for(int i = 0;i < n;i++)
{
gets(map[i]);
}
ok = false;
for(int i = 0;i < n;i++)
for(int j = 0;j < m;j++)
{
if(!vis[i][j])//被访问过的点没有再进行dfs的必要,因为之前这些点的所有方向都已被尝试过
{
dfs(i,j,-1,-1,map[i][j]);
if(ok)
{
printf("Yes\n");
goto out;
}
}
}
out:
if(!ok)
printf("No\n");
}
return 0;
}