题解 Y

传送门

首先发现每个状态可以被压成一个 \(\{(x_1, y_1), (x_2, y_2)\}\) 的二元组,分别表示空白格子和指定格子的位置
于是可以状压,复杂度 \(O(qn^2m^2)\),因为-1判错了挂了十分
其实这个方法开O2可以AC

然后正解:
貌似是处理这种地图固定,状压移动求最短路且询问数很多的题的一种套路
发现指定格子要想移动,空白格子肯定得在它旁边
于是这样的状态有 \(4nm\) 种,而且从某些状态可以走一定步数到达下一个状态
于是将这些状态抽离出来,在这些状态上建图,就可以用最短路求出到达某种状态的最小步数
发现初始状态下空白格子不一定在指定格子旁边,所以BFS把它挪过去
注意特判初始指定格子就在目标格子上的情况

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define fir first
#define sec second
#define make make_pair
// #define int long long

char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, k;
bool mp[32][32];

namespace force{
	int dp[32][32][32][32], top;
	const int dlt[][2]={{-1,0},{0,1},{1,0},{0,-1}};
	struct st{int x1, y1, x2, y2; st(){} st(int a, int b, int c, int d):x1(a),y1(b),x2(c),y2(d){}}sta[30*30*30*30+10];
	queue<st> q;
	void solve() {
		int ex, ey, sx, sy, tx, ty;
		memset(dp, -1, sizeof(dp));
		for (int i=1; i<=k; ++i) {
			// cout<<"i: "<<i<<endl;
			ex=read(); ey=read(); sx=read(); sy=read(); tx=read(); ty=read();
			// memset(dp, -1, sizeof(dp));
			while (top) dp[sta[top].x1][sta[top].y1][sta[top].x2][sta[top].y2]=-1, --top;
			while (q.size()) q.pop();
			dp[sx][sy][ex][ey]=0;
			sta[++top]=st(sx, sy, ex, ey);
			q.push(st(sx, sy, ex, ey));
			st u;
			while (q.size()) {
				u=q.front(); q.pop();
				// cout<<1<<endl;
				// cout<<u.x1<<' '<<u.y1<<' '<<u.x2<<' '<<u.y2<<endl;
				int dp_this=dp[u.x1][u.y1][u.x2][u.y2];
				for (int j=0,x,y; j<4; ++j) {
					// cout<<"j: "<<j<<endl;
					x=u.x2+dlt[j][0], y=u.y2+dlt[j][1];
					// cout<<"xy: "<<x<<' '<<y<<endl;
					if (x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]) {
						if (x==u.x1&&y==u.y1) {
							if (dp[u.x2][u.y2][u.x1][u.y1]==-1) {
								dp[u.x2][u.y2][u.x1][u.y1]=dp_this+1;
								sta[++top]=st(u.x2, u.y2, u.x1, u.y1);
								q.push(st(u.x2, u.y2, u.x1, u.y1));
								if (u.x2==tx&&u.y2==ty) {
									printf("%d\n", dp_this+1);
									goto jump;
								}
							}
						}
						else {
							if (dp[u.x1][u.y1][x][y]==-1) {
								dp[u.x1][u.y1][x][y]=dp_this+1;
								sta[++top]=st(u.x1, u.y1, x, y);
								q.push(st(u.x1, u.y1, x, y));
							}
						}
					}
				}
			}
			printf("%d\n", dp[tx][ty][ex][ey]);
			jump: ;
		}
	}
}

namespace task{
	int dp[32][32], f[32][32][4][4], head[4096], dis[4096], size;
	bool vis[N];
	struct edge{int to, next, val;}e[32768];
	inline void add(int s, int t, int w) {e[++size].to=t; e[size].val=w; e[size].next=head[s]; head[s]=size;}
	const int dlt[][2]={{-1,0},{1,0},{0,1},{0,-1}};
	queue<pair<int, int>> q;
	queue<int> q2;
	void bfs(int sx, int sy, int dx, int dy) {
		memset(dp, -1, sizeof(dp));
		while (q.size()) q.pop();
		dp[sx][sy]=0; dp[dx][dy]=INF;
		q.push(make(sx, sy));
		pair<int, int> u;
		while (q.size()) {
			u=q.front(); q.pop();
			int dp_this=dp[u.fir][u.sec];
			for (int i=0,x,y; i<4; ++i) {
				x=u.fir+dlt[i][0], y=u.sec+dlt[i][1];
				if (x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]&&dp[x][y]==-1) {
					dp[x][y]=dp_this+1;
					q.push(make(x, y));
				}
			}
		}
	}
	inline int num(int i, int j, int k) {return 4*((i-1)*m+j)+k;}
	void spfa() {
		int u;
		while (q2.size()) {
			u=q2.front(); q2.pop();
			vis[u]=0;
			for (int i=head[u],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (dis[u]+e[i].val < dis[v]) {
					dis[v]=dis[u]+e[i].val;
					if (!vis[v]) q2.push(v), vis[v]=1;
				}
			}
		}
	}
	void solve() {
		int ex, ey, sx, sy, tx, ty;
		memset(dp, -1, sizeof(dp));
		memset(f, 0x3f, sizeof(f));
		memset(head, -1, sizeof(head));
		for (int i=1; i<=n; ++i) {
			for (int j=1; j<=m; ++j) if (mp[i][j]) {
				for (int k=0,x,y; k<4; ++k) {
					x=i+dlt[k][0], y=j+dlt[k][1];
					if (!mp[x][y]) continue;
					bfs(x, y, i, j);
					// cout<<"bfs: "<<i<<' '<<j<<endl;
					// cout<<"dp: "<<endl;
					// for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<dp[i][j]<<' '; cout<<endl;}
					for (int h=0,s,t,t1,t2; h<4; ++h) if (h!=k) {
						s=i+dlt[h][0], t=j+dlt[h][1];
						if (!mp[s][t] || dp[s][t]==-1 || dp[s][t]==INF) continue;
						f[i][j][k][h]=dp[s][t];
						// printf("f[%d][%d][%d][%d]=%d\n", i, j, k, h, f[i][j][k][h]);
						t1=num(i, j, k); t2=num(i, j, h);
						add(t1, t2, dp[s][t]); add(t2, t1, dp[s][t]);
						// printf("add: (%d, %d, %d), (%d, %d, %d)=%d\n", i, j, k, i, j, h, dp[s][t]);
					}
					add(num(i, j, k), num(x, y, k^1), 1);
					add(num(x, y, k^1), num(i, j, k), 1);
					// printf("add: (%d, %d, %d), (%d, %d, %d)=%d\n", x, y, k^1, i, j, k, 1);
				}
			}
		}
		for (int i=1; i<=k; ++i) {
			ex=read(); ey=read(); sx=read(); sy=read(); tx=read(); ty=read();
			bfs(ex, ey, sx, sy);
			if (sx==tx&&sy==ty) {puts("0"); continue;}
			memset(dis, 0x3f, sizeof(dis));
			for (int j=0,x,y; j<4; ++j) {
				x=sx+dlt[j][0], y=sy+dlt[j][1];
				if (!mp[x][y] || dp[x][y]==-1) continue;
				dis[num(sx, sy, j)]=dp[x][y];
				// cout<<"pre: "<<dp[x][y]<<endl;
				q2.push(num(sx, sy, j));
			}
			spfa();
			// cout<<"dis: "<<dis[num(2, 2, 0)]<<endl;
			int ans=INF;
			for (int j=0,x,y; j<4; ++j) {
				x=tx+dlt[j][0], y=ty+dlt[j][1];
				if (!mp[x][y]) continue;
				ans=min(ans, dis[num(tx, ty, j)]);
			}
			printf("%d\n", ans==INF?-1:ans);
			jump: ;
		}
	}
}

signed main()
{
	// freopen("y.in", "r", stdin);
	// freopen("y.out", "w", stdout);

	n=read(); m=read(); k=read();
	for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) mp[i][j]=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2021-10-18 09:44  Administrator-09  阅读(0)  评论(0编辑  收藏  举报