day2 打卡
这道题数据范围好小,为了弄明白到底是如何记录路径的,这次特意没有乱搞。
昨天找了好久,输出路径的原理,后来发现没啥东西,就是用vis数组记住你这条路怎么来的就行,走的是上,是下,是左,还是右。然后从终点在推回去,把路径放到栈中,然后输出,这样就是起点到终点的最短路径。
一开始我在结构体里写了初始化,我本地编译器还报错了,我还以为我思路写错了(😓
AC代码(广搜版):
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int a[10][10];
int vis[10][10];
struct node{
int x,y;
/*
node(int x,int y){
this->x=x;
this->y=y;
}
*/
}st,now;
int dir[4][2]={
{1,0},{0,1},{-1,0},{0,-1}
};
void print(int x,int y){
if(vis[x][y]!=-1){
int xx=x-dir[vis[x][y]-1][0];
int yy=y-dir[vis[x][y]-1][1];
print(xx,yy);
printf("(%d, %d)\n",x,y);
}else{
printf("(0, 0)\n");
}
return ;
}
bool check(int x,int y){
if(x>4||x<0||y>4||y<0) return 0;
return 1;
}
void bfs(){
queue<node> q;
st.x=0;
st.y=0;
q.push(st);
while(!q.empty()){
st=q.front();
q.pop();
if(st.x==4&&st.y==4){
print(4,4);
return ;
}
for(int i=1;i<=4;i++){
now.x=st.x+dir[i-1][0];
now.y=st.y+dir[i-1][1];
if(check(now.x,now.y)&&vis[now.x][now.y]==0&&a[now.x][now.y]==0){
q.push(now);
vis[now.x][now.y]=i;
}
}
}
}
int main(){
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
cin>>a[i][j];
}
}
vis[0][0]=-1;
bfs();
return 0;
}
AC代码(深搜版):
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int a[10][10];
int vis[10][10];
struct node{
int x,y;
/*
node(int x,int y){
this->x=x;
this->y=y;
}
*/
}st,now;
int dir[4][2]={
{1,0},{0,1},{-1,0},{0,-1}
};
void print(int x,int y){
if(vis[x][y]!=-1){
int xx=x-dir[vis[x][y]-1][0];
int yy=y-dir[vis[x][y]-1][1];
print(xx,yy);
printf("(%d, %d)\n",x,y);
}else{
printf("(0, 0)\n");
}
return ;
}
bool check(int x,int y){
if(x>4||x<0||y>4||y<0) return 0;
return 1;
}
void dfs(int x,int y){
if(x==4&&y==4){
print(4,4);
return ;
}
for(int i=1;i<=4;i++){
int xx=x+dir[i-1][0];
int yy=y+dir[i-1][1];
if(check(xx,yy)&&vis[xx][yy]==0&&a[xx][yy]==0){
vis[xx][yy]=i;
dfs(xx,yy);
}
}
}
int main(){
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
cin>>a[i][j];
}
}
vis[0][0]=-1;
dfs(0,0);
return 0;
}
然后做一个延深,此题数据毕竟太小。
我用第十届蓝桥杯c++b组的一道填空题再来巩固一下这个记忆路径的搜索。
题目地址:E题
同样用了深搜和广搜,因为本题的要求就是输出方向,也更贴近记忆路径的本质,我们可以采取两种方式:一是直接用字符串记录,及时累加,遇到一个方向就在这一个点要上下左右走的时候直接用字符串存上当前要走的方向;二是用数组存起来,然后再用栈倒叙输出一遍,判断数组中的方向,确定字符。
AC代码(广搜,字符串直接累加):
#include<bits/stdc++.h>
using namespace std;
int dir[4][2]={{1,0},{0,-1},{0,1},{-1,0}};
int a[55][55];
int vis[55][55];
char opp[5]={'D','L','R','U'};//下左右上 字典序
struct node{
int x,y;
string ans;
}st,now;
bool check(int x,int y){
if(x<0||x>=30||y<0||y>=50) return 0;
return 1;
}
void bfs(){
queue<node> q;
now.x=0;
now.y=0;
now.ans="";
q.push(now);
vis[0][0]=1;
while(!q.empty()){
now=q.front();
q.pop();
if(now.x==30-1&&now.y==50-1){
cout<<now.ans;
return ;
}
for(int i=0;i<4;i++){
st.x=now.x+dir[i][0];
st.y=now.y+dir[i][1];
st.ans=now.ans+opp[i];
if(check(st.x,st.y)&&vis[st.x][st.y]==0&&a[st.x][st.y]==0){
q.push(st);
vis[st.x][st.y]=1;
}
}
}
return ;
}
int main(){
string s;
for(int i=0;i<30;i++){
cin>>s;
for(int j=0;j<50;j++){
a[i][j]=s[j]-'0';
}
}
bfs();
return 0;
}
有两个坑点,一是给定的本地数据是连在一起的,直接用int读入会默认成大整数,应该采取字符串处理;二是字典序最小输出,我们用opp数组按字典序从小到大排好,同时搜索所用的数组也要与之相对应,如D对应(1,0),L对应(0,-1)。
AC代码(深搜,数组记录方向):
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=55;
int ans;
int dir[4][2]={
{1,0},{0,-1},{0,1},{-1,0}
};
struct node{
int x,y;
}path[maxn*maxn],now;
int a[maxn][maxn];
int vis[maxn][maxn];
void output(){
string s;
int tx=0,ty=0;
for(int i=1;i<=ans;i++){
int px=path[i].x-tx;
int py=path[i].y-ty;
if(px==-1&&py==0) s+='U';
else if(px==1&&py==0) s+='D';
else if(px==0&&py==-1) s+='L';
else if(px==0&&py==1) s+='R';
tx=path[i].x;
ty=path[i].y;
}
cout<<s<<endl;
return ;
}
bool judge(int x,int y){
if(x>=1&&y>=1&&x<=30&&y<=50&&vis[x][y]!=1&&a[x][y]!=1){
return 1;
}
return 0;
}
void dfs(int x,int y,int step){
if(x==30&&y==50){
ans=step;
now.x=30;
now.y=50;
path[step]=now;
return ;
}
for(int i=0;i<4;i++){
int xx=x+dir[i][0];
int yy=y+dir[i][1];
now.x=xx;
now.y=yy;
if(judge(xx,yy)){
vis[xx][yy]=1;
path[step]=now;
dfs(xx,yy,step+1);
vis[xx][yy]=0;
}
}
}
int main(){
string s;
for(int i=1;i<=30;i++){
cin>>s;
for(int j=1;j<=50;j++){
a[i][j]=s[j]-'0';
}
}
dfs(1,1,0);
output();
return 0;
}
(最后的代码好像有坑,之前练蓝桥杯的时候写的,不想调了,逃)