列表

详情


NC205305. 迷宫

描述

SuperSodaSea 在玩一个走迷宫的游戏。迷宫是一个大小为 的矩阵,从上到下依次给行编号为 ,从左到右依次给列编号为
游戏规则很简单:从起点出发,每步操作可以移动到上、下、左、右四个方向的空地上,直到终点。
为了增加游戏的难度,在这个游戏中,从起点到终点并不一定会有直接的通路。当然,相对应地,玩家可以使用名为“穿越”的技能:从一块空地移动到距离至多为 d 另一片空地上(起点和终点也视为空地),无论中间是否有障碍。
在使用技能时的距离是指“切比雪夫距离”,即如果从 (x_1, y_1) 穿越到 (x_2, y_2) 需要满足 。“穿越”只能最多使用一次,使用时算一步操作。
现在你需要帮 SuperSodaSea 计算出给定的迷宫,他最少需要多少步才能到达终点,并给出一个方案。

输入描述

第一行包含 3 个整数 n, m, d (, ),中间以空格分隔,分别表示地图的行数、列数和穿越的最大距离。
接下来 n 行,每行包含一个长度为 m 的字符串,表示地图。
其中,. 表示空地,X 表示障碍,S 表示起点,T表示终点。
输入保证有且仅有一个起点和一个终点。

输出描述

第一行输出一个整数 t 表示最少所需要的步骤。
接下来 t + 1 行,每行输出两个整数 x_i, y_i,中间以空格分隔, 表示每一步所经过的坐标。其中,第一行和最后一行应分别对应起点和终点。
特别地,如果没有可以走到终点的方案,则在一行输出 -1。
答案不唯一,任何符合要求的答案都会被判为正确。

示例1

输入:

5 7 2
SXX....
.XX.XX.
.XXXXX.
.XX.XX.
....XXT

输出:

17
0 0
1 0
2 0
3 0
4 0
4 1
4 2
4 3
3 3
1 3
0 3
0 4
0 5
0 6
1 6
2 6
3 6
4 6

示例2

输入:

5 7 0
SXX....
.XX.XX.
.XXXXX.
.XX.XX.
....XXT

输出:

-1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 1139ms, 内存消耗: 174324K, 提交时间: 2020-04-18 17:07:43

#include<bits/stdc++.h>
using namespace std;
#define M 2005
char dr[M][M];
int s1,e1,s2,e2;
int fx[]={0,0,1,-1,1,-1,0,0};
int dis[M][M][2],n,m;
struct hh{
	int x,y,w;
}sk[M*M];
int q1[M],q2[M],mi[M][M],sl[M][M],fa1[M][M][2],fa2[M][M][2],ans1[M*M],ans2[M*M],cnt,pt1[M][M],pt2[M][M];
void Bfs(int x,int y,int f){
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)dis[i][j][f]=1e9;
	int l=1,r=0;sk[++r]=(hh){x,y,0};dis[x][y][f]=0;
	while(l<=r){
		hh p=sk[l++];
		for(int i=0;i<4;++i){
			int tx=p.x+fx[i],ty=p.y+fx[i+4];
			if(tx<1||tx>n||ty<1||ty>m)continue;
			if(dr[tx][ty]=='X')continue;
			if(p.w+1<dis[tx][ty][f]){
				dis[tx][ty][f]=p.w+1;
				fa1[tx][ty][f]=p.x;
				fa2[tx][ty][f]=p.y;
				sk[++r]=(hh){tx,ty,p.w+1};
			}
		}
	}
}
void dfs(int x,int y,int f){
	ans1[++cnt]=x-1;ans2[cnt]=y-1;
	if(fa1[x][y][f])dfs(fa1[x][y][f],fa2[x][y][f],f);
}
int main(){
	int d;scanf("%d%d%d",&n,&m,&d);
	for(int i=1;i<=n;++i)scanf("%s",dr[i]+1);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			if(dr[i][j]=='S')s1=i,e1=j;
			else if(dr[i][j]=='T')s2=i,e2=j;
	Bfs(s1,e1,0);Bfs(s2,e2,1);
	int ans=dis[s2][e2][0];
	for(int i=1;i<=m;++i){
		int l=1,r=0;
		for(int j=1;j<=n;++j){
			while(r>=l&&dis[q1[r]][q2[r]][1]>dis[j][i][1])--r;
			q1[++r]=j;q2[r]=i;
			while(l<=r&&j-q1[l]>d+d)++l;
			mi[j][i]=dis[q1[l]][q2[l]][1];
			pt1[j][i]=q1[l];
			if(j==n){
				for(int k=d-1;k>=0;--k){
					while(l<=r&&j-q1[l]>k+d)++l;
					sl[k][i]=dis[q1[l]][q2[l]][1];
					pt2[k][i]=q1[l];
				}
			}
		}
	}
	int p1=s2,p2=e2,p3=s2,p4=e2;
	for(int i=1;i<=n-d;++i){
		int p=i+d,l=1,r=0;
		for(int j=1,tp=1;j<=m;++j){
			while(tp<=m&&abs(tp-j)<=d){
				while(r>=l&&mi[q1[r]][q2[r]]>mi[p][tp])--r;
				q1[++r]=p;q2[r]=tp;++tp;
			}
			while(l<=r&&j-q2[l]>d)++l;
			if(dis[i][j][0]+mi[q1[l]][q2[l]]+1<ans){
				ans=dis[i][j][0]+mi[q1[l]][q2[l]]+1;
				p1=i,p2=j;p3=pt1[q1[l]][q2[l]];p4=q2[l];
			}
		}
	}
	for(int i=max(1,n-d+1);i<=n;++i){
		int p=n-i,l=1,r=0;
		for(int j=1,tp=1;j<=m;++j){
			while(tp<=m&&abs(tp-j)<=d){
				while(r>=l&&sl[p][q2[r]]>sl[p][tp])--r;
				q2[++r]=tp;++tp;
			}
			while(l<=r&&j-q2[l]>d)++l;
			if(dis[i][j][0]+sl[p][q2[l]]+1<ans){
				ans=dis[i][j][0]+sl[p][q2[l]]+1;
				p1=i,p2=j;p3=pt2[p][q2[l]],p4=q2[l];
			}
		}
	}
	if(ans==1e9){
		puts("-1");
		return 0;
	}
	printf("%d\n",ans);
	dfs(p1,p2,0);
	for(int i=cnt;i>=1;--i)printf("%d %d\n",ans1[i],ans2[i]);
	cnt=0;
	dfs(p3,p4,1);
	for(int i=1;i<=cnt;++i){
		if(p1==p3&&p2==p4&&i==1)continue;
		printf("%d %d\n",ans1[i],ans2[i]);
	}
}

C++11(clang++ 3.9) 解法, 执行用时: 748ms, 内存消耗: 154956K, 提交时间: 2020-04-18 14:30:44

#include<bits/stdc++.h>
using namespace std;
#define N 2003
bool Bar;
int n,m,a,sx,sy,ex,ey,K[N][N],x,y,b,now;
int A_F[N][N],B_F[N][N],head,tail,k,r;
int Dis[N*N*2],Fr[N*N*2],Mk[N][N][2];
int Rx[5]= {0,0,-1,1};
int Ry[5]= {-1,1,0,0};
struct V {
	int x,y,k;
} Q[N*N*2],q;
char S[N];
bool Ka;
int Find_a(int i,int j) {
	return A_F[i][j]==j?j:A_F[i][j]=Find_a(i,A_F[i][j]);
}
int Find_b(int i,int j) {
	return B_F[i][j]==i?i:B_F[i][j]=Find_b(B_F[i][j],j);
}
int main() {
//	printf("%lf\n",(&Ka-&Bar)/1024.0/1024.0);
//	freopen("A.in","r",stdin);
//	freopen("try.out","w",stdout);
	scanf("%d %d %d",&n,&m,&a);
	for(int i=1; i<=n; ++i) {
		scanf("%s",S+1);
		for(int j=1; j<=m; ++j) {
			if(S[j]=='S')sx=i,sy=j;
			else if(S[j]=='T')ex=i,ey=j;
			else K[i][j]=S[j]=='X';
		}
	}
	for(int i=1; i<=n; ++i)for(int j=1; j<=m+1; ++j)A_F[i][j]=j;
	for(int i=1; i<=n+1; ++i)for(int j=1; j<=m; ++j)B_F[i][j]=i;
	Q[tail=1]=(V)<%sx,sy,0%>,Mk[sx][sy][0]=1;
	while(head<tail) {
		q=Q[++head];
		for(int z=0; z!=4; ++z) {
			x=q.x+Rx[z],y=q.y+Ry[z];
			if(x&&y&&x<=n&&y<=m&&!Mk[x][y][q.k]&&!K[x][y]) {
				Mk[x][y][q.k]=tail+1,Dis[tail+1]=Dis[head]+1;
				Q[++tail]=(V)<%x,y,q.k%>,Fr[tail]=head;
			}
		}
		if(q.k)continue;
		r=min(m,q.y+a);
		for(int j=Find_a(q.x,max(1,q.y-a)); j<=r;) {
			b=min(n,q.x+a);
			for(int k=Find_b(max(1,q.x-a),j); k<=b;) {
//				printf("%d %d %d %d %d\n",q.x,q.y,j,k,a);
				if(!Mk[k][j][1]&&!K[k][j]) {
					Mk[k][j][1]=tail+1,Dis[tail+1]=Dis[head]+1;
					Q[++tail]=(V)<%k,j,1%>,Fr[tail]=head;
				}
				B_F[k][j]=k+1,k=Find_b(k,j);
			}
			A_F[q.x][j]=j+1,j=Find_a(q.x,j);
		}
	}
	if(Mk[ex][ey][1]||Mk[ex][ey][0]) {
		if(Mk[ex][ey][0])now=Mk[ex][ey][0];
		if(!now||(Dis[now]>Dis[Mk[ex][ey][1]]&&Mk[ex][ey][1]))now=Mk[ex][ey][1];
		printf("%d\n",Dis[now]);
		while(now) Q[tail--]=Q[now],now=Fr[now];
		for(int i=tail+1; i<=head; ++i) {
			printf("%d %d\n",Q[i].x-1,Q[i].y-1);
		}
	} else puts("-1");
	return 0;
}

上一题