搜索五题共一解
搜索五题
难度:中等
题目分析
1.血色先锋队
给定一个大小为 $n\times m$ 的矩阵 $A$ ,有 $a$ 个坐标为 $(x_i,y_i)$ 的人,每一秒会将是否感染的状态传递给上下左右的人。现在请你求出 $b$ 个坐标为 $(X_i,Y_i)$ 的人的感染时间。
2.路障
给定一个大小为 $n^2$ 的矩阵 $A$ ,一个人要从 $(1,1)$ 走到 $(n,n)$ ,期间的 $2n-2$ 秒内,每一秒在 $(x_i,y_i)$ 上会出现一个路障,求这个人是否能成功走到 $(n,n)$ 。
3.[USACO06OCT] Cows on Skates G
给定一个大小为 $r\times c$ 的矩阵 $A$ ,一个人要从 $(1,1)$ 走到 $(r,c)$ ,其中若 $A_{i,j}$ 的值是 '.' ,则可以通过,反之无法通过。请输出其中一种路径。
4.走迷宫
给定一个大小为 $m\times n$ 的矩阵 $A$,一个人要从 $(sx,sy)$ 走到 $(tx,ty)$ ,若 $A_{i,j}$ 的值是 1 ,则可以通过,反之无法通过。请输出所有的路径。
5.棋盘
给定一个大小为 $m^2$ 的染色矩阵 $A$ ,其中从有色走到有色但颜色不同的格子需要 1 点代价,从有色走到相同颜色的格子不需要代价,从有色走到无色的格子需要 2 点代价,且这种格子路过之后会还原成无色。求一个人从 $(1,1)$ 走到 $(m,m)$ 的最小代价;若无法到达,输出 -1。
思路分析
1.血色先锋队
这题我们可以采用 BFS 的策略,将每个感染源(感染者)的坐标放入队列;当队列不空时,则说明没有全部感染。接着我们定义方向数组,向上下左右的人进行传染,最后预处理出所有人的感染时间 $T[i][j]$ ,在询问的时候输出相应的 $T[x][y]$ 即可。
2.路障
这题我们也可以采用 BFS 的策略,将每个点的坐标 $(x,y)$ 以及对应的走到的时间 $t$ 放入队列(定义一个结构体)。接着我们将所有的路障下落时间提前存放到数组中,再在每个单位时间内将它标记。接着进行移动,更新即可。
3.[USACO06OCT] Cows on Skates G
这题我使用的算法是 DFS。这题比较简单,而且数据范围非常人性。我们只需要常规跑 DFS,但是要定一个答案数组 $ans[N][2]$,$ans[i][0]$ 存放当前合法的 $x$ 坐标, $ans[i][1]$ 存放当前合法的 $y$ 坐标。最后当 $x=r$ 且 $y=c$ 时,从 1 到 $cnt$ 依次输出 $ans[i][0],ans[i][1]$ 即可。
4.走迷宫
这题我们还是可以常规 DFS。思路和第三题差不多,只不过我们不用判断此时的 $x,y$ 是否合法,因为如果超出边界,$A[x][y]$ 必然为0(而且如果加判断会神秘 WA 掉)。接着和第三题都一样。
5.棋盘
依旧是 DFS。直接定义一个 $d[N][N]$ 数组,其中 $d[i][j]$ 表示 $(1,1)->(i,j)$ 的最小价值,是我们剪枝的依据。接着定义 $coin=Maxint $ ,在 dfs() 中更新即可。最后如果 $coin==Maxint$ 则说明走不到,输出 -1,反之输出 $coin$ 。
Code Share
1.血色先锋队
#include<bits/stdc++.h> using namespace std; const int N=555; int ans[N][N]; int dx[]={0,0,0,-1,1},dy[]={0,1,-1,0,0}; int n,m,a,b; bool v[N][N]; struct node{ int x,y,t; }; int main() { queue<node> q; scanf("%d %d %d %d",&n,&m,&a,&b); while(a--) { int x,y; scanf("%d %d",&x,&y); node p; p.x=x,p.y=y,p.t=0; q.push(p); v[x][y]=1; } while(q.size()) { node now=q.front(); node p; for(int i=1;i<=4;i++) { now=q.front(); int x=now.x,y=now.y,t=now.t; int xx=x+dx[i],yy=y+dy[i]; if(xx>=1 && xx<=n && yy>=1 && yy<=m && !v[xx][yy]) { v[xx][yy]=1; p.x=xx; p.y=yy; p.t=t+1; q.push(p); } } ans[now.x][now.y]=now.t; q.pop(); } while(b--) { int x,y; scanf("%d %d",&x,&y); printf("%d\n",ans[x][y]); } return 0; }
2.路障
#include<bits/stdc++.h> using namespace std; const int N=1010,M=2020; int stopx[M],stopy[M]; int dx[]={0,0,0,-1,1},dy[]={0,1,-1,0,0}; int T; struct node{ int x,y,t; }; bool v[N][N],v2[N][N]; int main() { scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=2*n-2;i++) scanf("%d %d",&stopx[i],&stopy[i]); memset(v,0,sizeof(v)); memset(v2,0,sizeof(v2)); //bfs v[1][1]=1; bool flag=0; queue<node> q; node p,l; p.x=1,p.y=1,p.t=0; q.push(p); while(q.size()) { p=q.front(); q.pop(); int x=p.x; int y=p.y; int t=p.t; if(x==n && y==n) { flag=1; break; } v2[stopx[t]][stopy[t]]=1; for(int i=1;i<=4;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if(xx>=1 && xx<=n && yy>=1 && yy<=n && !v[xx][yy] &&!v2[xx][yy]) { l.x=xx; l.y=yy; l.t=t+1; v[xx][yy]=1; q.push(l); } } } if(flag) printf("Yes\n"); else printf("No\n"); } return 0; }
3.[USACO06OCT] Cows on Skates G
#include<bits/stdc++.h> using namespace std; const int N=120,M=80; int dx[]={0,0,0,-1,1}; int dy[]={0,-1,1,0,0}; int r,c,cnt=1,ans[100010][2]; bool v[N][M]; char a[N][M]; void dfs(int x,int y) { if(x==r && y==c) { for(int i=1;i<=cnt;i++) printf("%d %d\n",ans[i][0],ans[i][1]); return ; } for(int i=1;i<=4;i++) { int xx=x+dx[i],yy=y+dy[i]; if(xx>=1 && xx<=r && yy>=1 && yy<=c && !v[xx][yy] && a[xx][yy]=='.') { v[xx][yy]=1; cnt++; ans[cnt][0]=xx; ans[cnt][1]=yy; dfs(xx,yy); cnt--; } } } int main() { scanf("%d %d",&r,&c); for(int i=1;i<=r;i++) { char s[N]; scanf("%s",s+1); for(int j=1;j<=c;j++) a[i][j]=s[j]; } ans[1][0]=ans[1][1]=1; v[1][1]=1; dfs(1,1); return 0; }
4.走迷宫
#include<bits/stdc++.h> using namespace std; const int N=16; int a[N][N],p[50050][2]; int dx[5]={0,0,-1,0,1}; int dy[5]={0,-1,0,1,0}; int m,n,cnt; bool v[N][N],flag; int sx,sy,tx,ty; void dfs(int x,int y) { if(x==tx && y==ty) { flag=1; for(int i=1;i<=cnt;i++) printf("(%d,%d)->",p[i][0],p[i][1]); printf("(%d,%d)\n",tx,ty); return ; } for(int i=1;i<=4;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if(!v[xx][yy] && a[xx][yy]==1) { ++cnt; v[x][y]=1; p[cnt][0]=x; p[cnt][1]=y; dfs(xx,yy); v[x][y]=0; --cnt; } } } int main() { scanf("%d %d",&m,&n); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); scanf("%d %d\n%d %d",&sx,&sy,&tx,&ty); dfs(sx,sy); if(flag==0) { printf("-1"); return 0; } return 0; }
5.棋盘
#include<bits/stdc++.h> using namespace std; const int M=101; int a[M][M],n,m,coin=0x7f7f7f7f; int color[M][M],d[M][M]; bool v[M][M]; int dx[]={0,1,-1,0,0},dy[]={0,0,0,1,-1}; void dfs(int x,int y,int now,bool magic) { if(x<1 || x>m || y<1 || y>m) return ; if(now>=d[x][y]) return ; d[x][y]=now; if(x==m && y==m) //走到终点 { coin=min(coin,now); return ; } for(int i=1;i<=4;i++) { int xx=x+dx[i]; int yy=y+dy[i]; //下一个格子有色 if(color[xx][yy]) { if(color[xx][yy]!=color[x][y]) dfs(xx,yy,now+1,false); else dfs(xx,yy,now,false); } //没有用魔法 else if(!magic) { color[xx][yy]=color[x][y]; dfs(xx,yy,now+2,true); color[xx][yy]=0; } } } int main() { memset(d,0x7f,sizeof(d)); scanf("%d %d",&m,&n); //(1,1)->(m,m) for(int i=1;i<=n;i++) { int x,y,c; scanf("%d %d %d",&x,&y,&c); color[x][y]=c+1; //c==0无色,c==1为红色,c==2为黄色 //小技巧:为了区分有色和无色 } dfs(1,1,0,false); printf("%d",coin==0x7f7f7f7f ? -1:coin); return 0; }