Bootstrap

[Exam][DFS] 10.26 棋盘行走

Date:2019/10/27

在这里插入图片描述

这道题还算做的可以,一看题面就知道是一道最最最普通的DFS
所以递归位置,并注意打标记,看跑完一次后次数有没有 c n t ≥ 4 cnt\geq 4 cnt4就可以了

坑点

  • 字符地图的输入,字符地图输入需要判定不是换行符,如果不判定的话会很糟糕
  • 每次递归时,如果满足条件就直接结束整个程序,不要继续递归了
    因为有一个点50*50的图全是A

AC code[DFS]

//Author:PhilFan;
#include<bits/stdc++.h>
using namespace std;
int n,m,tot;
int movx[4]={0,1,0,-1};
int movy[4]={1,0,-1,0};//移动 
int mapx[55][55];//地图 
int fx,fy;
bool vis[55][55];
//-----------------------------------------------------------------------------
void dfs(int x,int y,int cnt){
	if(x == fx && y == fy && cnt != 0){			//跑完一遍并且不是一开始就跑完
		if(cnt >= 4){							//如果次数大于4,就输出并直接退出
			cout<<"Yes";
			exit(0);
		}
	}
	int xx,yy;
	for(int i = 0; i <= 3;i++){					//跑地图写法,比较经典,详见迷宫
		xx = x+movx[i];
		yy = y+movy[i];
		if(xx>=1 && xx <= n && yy >= 1 && yy <= m && vis[xx][yy]==0 && mapx[xx][yy] == mapx[x][y]){
			vis[xx][yy] = 1;
			dfs(xx,yy,cnt+1);
			vis[xx][yy] = 0;
		}
	}
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i = 1; i <= n;i++){		字符地图输入,恶心心 
		getchar();
		for(int j = 1; j <= m;j++){
			char a;
			a = getchar();
			while(a < 'A' || a >'Z'){a = getchar();}
			mapx[i][j] = a - 'A';
		}
	}

	for(int i = 1; i <= n;i++){
		for(int j = 1; j <= m;j++){
			fx = i,fy = j;
			memset(vis,0,sizeof(vis));
			dfs(i,j,0);
		}
	}	
	cout<<"No";
	return 0;
}

联通图的写法(Form zzc)

主要思路:为上下左右搜索 + 打标记 未走过的地方为0

以一个之前从未dfs过的字母为开头进行搜索,与其联通的所有字母全部搜索后若无回到起点的字母,则其中的所有联通的字母全部不成立,之后不进行搜索

#include<bits/stdc++.h>
using namespace std;
const int maxn = 60;
int n,m,xx[6]={0,1,-1,0,0},yy[6]={0,0,0,1,-1},a_x,a_y;
char f[maxn][maxn];
int vis[maxn][maxn];//仍代表标记 方式改变 -1代表走过 0 为未走,搜索过程中以1……n代表走的步数

void dfs(int x,int y,int k,char j,int num){
    if(num >= 4){
        for(int i = 1; i <= 4; i++){
            if(vis[x + xx[i]][y + yy[i]] == -1 || vis[x + xx[i]][y + yy[i]] == 0 )continue;
            if(vis[x][y] - vis[x + xx[i]][y + yy[i]] >= 3){
                    printf("Yes");//一旦出现回路立刻输出Yes 并结束整个程序,可减少运行次数
                    exit(0);
            }
        }
    }
    for(int i = 1; i <= 4; i++){
        if(vis[x + xx[i]][y + yy[i]] || x + xx[i] > n || x + xx[i] < 0 || y + yy[i] == m || y + yy[i] < 0)continue;
        if(f[x + xx[i]][y + yy[i]] == j){
            vis[x + xx[i]][y + yy[i]] = k + 1;
            dfs(x + xx[i],y + yy[i],k + 1,j,num + 1);//这里k变成k + 1
            vis[x + xx[i]][y + yy[i]] = 0;
        }
    }
    vis[x][y] = -1;//标记为-1
    return ;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n;i++)
    scanf("%s",f[i]);
    int cnt = 0;
    for(int  i = 1; i <= n ;i++){
        for(int j = 0; j < m;j++){
            if(vis[i][j] == -1)		continue;
            a_x = i;a_y = j;
            vis[i][j] = 1;//起始点为1
            dfs(i,j,1,f[i][j],1);
        }
    }
    printf("No");
    return 0;
}

老师的写法(From ivy_uu)

莫名奇妙快一点~
这!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,k;
const int N=64;
char arr[N][N];
bool flag = false;
bool visit[N][N];
int dirx[]={1,0,-1,0};
int diry[]={0,1,0,-1};

void dfs(int i,int j,int pi,int pj){
    if(visit[i][j]){
      flag = true;
      return;
    }
    visit[i][j]=true;
    for(int k=0;k<4;k++){
        int nextx = i+dirx[k];
        int nexty = j+diry[k];
        if(nextx>=0&&nextx<n&&nexty>=0&&nexty<m&&arr[i][j]==arr[nextx][nexty]){
            if(!(nextx==pi&&nexty==pj)){
              dfs(nextx,nexty,i,j);
            }
        }
    }
}

int main() {
    while(scanf("%d%d", &n, &m)==2){
        flag = false;
        for(int i=0;i<n;i++) scanf("%s", arr[i]);
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
              memset(visit,0,sizeof(visit));
              dfs(i,j,-1,-1);
              if(flag){
                cout<<"Yes"<<endl;
                break;
              }
            }
            if(flag) break;
        }
        if(!flag) cout<<"No"<<endl;
    }
    return 0;
}
;