ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【NOIP2013提高组】华容道

2021-01-18 08:35:38  阅读:214  来源: 互联网

标签:sy sx NOIP2013 tx int 华容道 提高 d% now


分析

一个比较显然的方式是
设 \(f_{i,j,x,y}\) 表示达到空格所处位置为 \((i,j)\) 且特殊格位置为 \(x,y\) 的状态的最少步数
一次可以交换空格和相邻格,代价为 \(1\),\(bfs\) 转移即可

但确实时间无法接受
我们想到转移时
当且仅当空格和特殊格相邻时特殊格的位置才可能变
所以我们设 \(f_{i,j,k}\) 表示特殊格位置为 \((i,j)\) 且空格在特殊格 \(k(k\in[0,3])\) 方向的最小步数
那么考虑两种转移
1.不动特殊格,空格从 \(k\) 方向转到 \(l\) 方向
2.空格与特殊格交换

第一种可以 \(bfs\) 预处理出来,记为 \(g_{i,j,k,l}\)
第二种代价为 \(1\)

因为有两种代价,所以我们要 \(spfa\) 转移
交换空格会使空格所在特殊格的方向相反
为方便表示我们用 \({1,2,3,4}\) 表示上下左右

\(Code\)

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

const int N = 35, INF = 0x3f3f3f3f;
int n, m, q, a[N][N], f[N][N][5], g[N][N][5][5], dis[N][N], vis[N][N][5];
int fx[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
struct node{int x, y, k;}Q[N*N*N];

inline int judge(int x, int y){return (x >= 1 && x <= n && y >= 1 && y <= m && a[x][y]);}

inline int bfs(int sx, int sy, int tx, int ty)
{
	memset(dis, 0x3f3f3f3f, sizeof dis);
	if (!judge(sx, sy) || !judge(tx, ty)) return INF;
	dis[sx][sy] = 0;
	int head = 0, tail = 1;
	Q[1] = node{sx, sy, 0};
	while (head < tail)
	{
		node now = Q[++head];
		if (dis[tx][ty] != INF) return dis[tx][ty];
		for(register int k = 0; k < 4; k++)
		{
			int x = now.x + fx[k][0], y = now.y + fx[k][1];
			if (judge(x, y) && dis[x][y] > dis[now.x][now.y] + 1) 
				dis[x][y] = dis[now.x][now.y] + 1, Q[++tail] = node{x, y, 0};
		}
	}
	return dis[tx][ty];
}

void prepare()
{
	for(register int i = 1; i <= n; i++)
	for(register int j = 1; j <= m; j++)
	{
		int tmp = a[i][j];
		a[i][j] = 0;
		for(register int k = 0; k < 4; k++)
		for(register int l = 0; l < 4; l++)
			g[i][j][k][l] = bfs(i + fx[k][0], j + fx[k][1], i + fx[l][0], j + fx[l][1]);
		a[i][j] = tmp;
	}
}

inline int spfa(int sx, int sy, int tx, int ty)
{
	memset(vis, 0, sizeof vis);
	int head = 0, tail = 0;
	for(register int k = 0; k < 4; k++)
	{
		int x = sx + fx[k][0], y = sy + fx[k][1];
		if (judge(x, y)) Q[++tail] = node{sx, sy, k}, vis[sx][sy][k] = 1;
	}
	while (head < tail)
	{
		node now = Q[++head];
		for(register int k = 0; k < 4; k++)
		{
			int x = now.x + fx[k][0], y = now.y + fx[k][1];
			if (judge(x, y) && f[x][y][k ^ 1] > f[now.x][now.y][now.k] + g[now.x][now.y][now.k][k] + 1)
			{
				f[x][y][k ^ 1] = f[now.x][now.y][now.k] + g[now.x][now.y][now.k][k] + 1;
				if (!vis[x][y][k ^ 1]) Q[++tail] = node{x, y, k ^ 1}, vis[x][y][k ^ 1] = 1;
			}
		}
		vis[now.x][now.y][now.k] = 0;
	}
	int ans = INF;
	for(register int k = 0; k < 4; k++) ans = min(ans, f[tx][ty][k]);
	return (ans == INF ? -1 : ans);
}

inline int solve()
{
	int ex, ey, sx, sy, tx, ty;
	scanf("%d%d%d%d%d%d", &ex, &ey, &sx, &sy, &tx, &ty);
	if (!judge(sx, sy) || !judge(tx, ty)) return -1;
	if (sx == tx && sy == ty) return 0;
	memset(f, 0x3f3f3f3f, sizeof f);
	int tmp = a[sx][sy];
	a[sx][sy] = 0;
	for(register int k = 0; k < 4; k++)
		f[sx][sy][k] = bfs(ex, ey, sx + fx[k][0], sy + fx[k][1]);
	a[sx][sy] = tmp;
	return spfa(sx, sy, tx, ty);
}

int main()
{
	scanf("%d%d%d", &n, &m, &q);
	for(register int i = 1; i <= n; i++)
		for(register int j = 1; j <= m; j++) scanf("%d", &a[i][j]);
	prepare();
	for(register int i = 1; i <= q; i++) printf("%d\n", solve());
}

标签:sy,sx,NOIP2013,tx,int,华容道,提高,d%,now
来源: https://www.cnblogs.com/leiyuanze/p/14291054.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有