洛谷P1189 SEARCH 题解

本题做法

  • DFS+剪枝。

思路

\(30pt\):朴素 DFS

定义 DFS 函数为:void dfs(int x,int y,int t),其中 \(x\)\(y\) 为当前搜索的坐标,\(t\) 代表当前要走第几步。

DFS 函数主体内每次都根据当前方向一直走,直到走到墙壁或尽头,则退出函数,可以使用 while 语句实现。
while(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[tx][ty]!='X')
随后就是正常的 DFS 函数了。

#include<bits/stdc++.h>

using namespace std;

const int N=55;
const int fx[5]={0,0,1,0,-1};
const int fy[5]={0,1,0,-1,0};

int n,m,q,sx,sy,dir[1005];
char mp[N][N],ans[N][N];
bitset<N> vis[1005][N]; 

void dfs(int x,int y,int t){
	if(t>q) {
		ans[x][y]='*';
		return;
	}
	int d=dir[t];
	int tx=x,ty=y;
	while(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[tx][ty]!='X'){
		tx+=fx[d];
		ty+=fy[d];
		if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[tx][ty]!='X'){
			dfs(tx,ty,t+1);
		}
	}
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {cin>>mp[i][j]; ans[i][j]=mp[i][j]; if(mp[i][j]=='*'){sx=i;sy=j;mp[i][j]=ans[i][j]='.';}}
	cin>>q;
	for(int i=1;i<=q;i++){
		string str;
		cin>>str;
		if(str=="EAST") dir[i]=1;
		else if(str=="SOUTH") dir[i]=2;
		else if(str=="WEST") dir[i]=3;
		else dir[i]=4;
	}
	dfs(sx,sy,1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cout<<ans[i][j];
		}
		cout<<endl;
	}
	return 0;
}

\(100pt\):DFS 剪枝

上面的代码交到洛谷上后只可以得 30 分,其余测试点全是 TLE。为了优化代码,我们可以采取搜索剪枝的方法来降低时间复杂度。

我们发现,只要 2 条路径在同一步经过同一个点,则这 2 条路后面的结果都是相同的。所以我们可以根据每个坐标的每一步中是否访问过来进行搜索剪枝。

定义 \(vis[t][x][y]\) 为在第 \(t\) 步时是否到达过 \((x,y)\) 坐标,每次 DFS 函数调用时将 \(vis[t][x][y]\) 设为 true,之后判断行走的标准再添加一个 \(\text{not }vis[t+1][tx][ty]\) 即可。

AC 代码

#include<bits/stdc++.h>

using namespace std;

const int N=55;
const int fx[5]={0,0,1,0,-1};
const int fy[5]={0,1,0,-1,0};

int n,m,q,sx,sy,dir[1005];
char mp[N][N],ans[N][N];
bitset<N> vis[1005][N]; 

void dfs(int x,int y,int t){
	if(t>q) {
		ans[x][y]='*';
		return;
	}
	vis[t][x][y]=1;
	int d=dir[t];
	int tx=x,ty=y;
	while(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[tx][ty]!='X'){
		tx+=fx[d];
		ty+=fy[d];
		if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&!vis[t+1][tx][ty]&&mp[tx][ty]!='X'){
			dfs(tx,ty,t+1);
		}
	}
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {cin>>mp[i][j]; ans[i][j]=mp[i][j]; if(mp[i][j]=='*'){sx=i;sy=j;mp[i][j]=ans[i][j]='.';}}
	cin>>q;
	for(int i=1;i<=q;i++){
		string str;
		cin>>str;
		if(str=="EAST") dir[i]=1;
		else if(str=="SOUTH") dir[i]=2;
		else if(str=="WEST") dir[i]=3;
		else dir[i]=4;
	}
	dfs(sx,sy,1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cout<<ans[i][j];
		}
		cout<<endl;
	}
	return 0;
}
posted @ 2025-04-21 19:23  2789617221guo  阅读(8)  评论(0)    收藏  举报