codeforces 510B dfs

题目链接: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;
}


你可能感兴趣的:(codeforces 510B dfs)