洛谷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;
}