不是锰锌不是妹子但是也想求查错
查看原帖
不是锰锌不是妹子但是也想求查错
150879
quest_2楼主2020/11/24 19:24

RT,调了近半天未过样例,求神仙救人。

注释很够,码风是vscode格式化的码风。

#include <bits/stdc++.h>
using namespace std;
const int MAX = 37;
int N, M, Q;
int num[MAX][MAX];
int dis[5][2] = {0, 0, 1, 0, -1, 0, 0, -1, 0, 1};
//方向

/*前向星组件*/
struct edge
{
	int next, to;
	int val;
} e[100007 << 1];
int head[100007], eid = 1;
void adde(int x, int y, int w)
{
	e[++eid].next = head[x];
	e[eid].to = y;
	e[eid].val = w;
	head[x] = eid;
}

#define PII pair<int, int>
#define MP make_pair
int v[MAX][MAX];
struct statu //存状态
{
	int x;
	int y;
	int dis;
	statu(int a = 0, int b = 0, int c = 0)
	{
		x = a;
		y = b;
		dis = c;
	}
};

/*get the dis from (x,y) to (xx,yy),can't pass (bx,by)*/
queue<statu> q;
int bfs(int x, int y, int xx, int yy, int bx, int by)
{
	if (x == xx && y == yy)
	{
		return 0; //若起终相同则距离为0
	}
	while (q.size())
	{
		q.pop(); //清空
	}
	for (int i = 1; i <= 4; i++)
	{
		int xx = x + dis[i][0], yy = y + dis[i][1];
		if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy] || (xx == bx && yy == by))
		{
			continue;
		}
		q.push(statu(xx, yy, 1)); //将四个方向都入队
	}
	memset(v, 0, sizeof(v)); //v即vis,记录某点是否被访问
	v[x][y] = 1;
	while (!q.empty())
	{
		statu u = q.front();
		q.pop();

		if (u.x == xx && u.y == yy) //若走到目标则返回距离
		{
			return u.dis;
		}
		if (v[u.x][u.y])
		{
			continue;
		}
		v[u.x][u.y] = 1;

		/*遍历四个方向,合法就入队*/
		for (int i = 1; i <= 4; i++)
		{
			int nx = u.x + dis[i][0], ny = u.y + dis[i][1];
			if (nx <= 0 || nx > N || ny <= 0 || ny > M || !num[nx][ny])
			{
				continue;
			}

			/*若该点是禁止被遍历的,就不走*/
			if (bx == nx && by == ny)
			{
				continue;
			}

			q.push(statu(nx, ny, u.dis + 1));
		}
	}
	return -1;
}

/*get id in matrix*/
int idx(int x, int y, int k) //获取编号
{
	return ((x - 1) * M + y - 1) * 4 + k;
}

/*link around blocks*/
void link_around(int x, int y)
{
	for (int i = 1; i <= 4; i++)
	{
		for (int j = i + 1; j <= 4; j++)
		{

			/*合法性判断*/
			int xx = x + dis[i][0], yy = y + dis[i][1];
			if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
			{
				continue;
			}
			xx = x + dis[j][0], yy = y + dis[j][1];
			if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
			{
				continue;
			}

			/*从一个方向转移到另一个方向*/
			int u = idx(x, y, i);
			int v = idx(x, y, j);
			int val = bfs(x + dis[i][0], y + dis[i][1], x + dis[j][0], y + dis[j][1], x, y);
			if (val != -1)
			{
				adde(u, v, val);
				adde(v, u, val);
			}
		}
	}
}

/*link to another*/
void link_another(int x, int y) //交换空格和某位置
{
	int xx = x + 1, yy = y;
	if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
	{
		;
	}
	else
	{
		int u = idx(x, y, 2);
		int v = idx(xx, yy, 1); //上下
		int dis = 1;
		adde(u, v, dis);
		adde(v, u, dis);
	}

	xx = x, yy = y + 1;
	if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
	{
		;
	}
	else
	{
		int u = idx(x, y, 4);
		int v = idx(xx, yy, 3); //左右
		int dis = 1;
		adde(u, v, dis);
		adde(v, u, dis);
	}
}

/*build the whole graph*/
void build_graph()
{
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= M; j++)
		{
			if (num[i][j])
			{
				link_around(i, j);
				link_another(i, j);
			}
		}
	}
}

const int MAXN = 1e5 + 7;

/*dij*/
#define PII pair<int, int>
#define MP make_pair
#define GI greater<PII>
int root = 0;
priority_queue<PII, vector<PII>, GI> pq;
int dist[MAXN << 1];
int vis[MAXN << 1];
void dij()
{
	memset(vis, 0, sizeof(vis));
	for (int i = 1; i <= N; i++)
	{
		dist[i] = 2147483647;
	}
	dist[root] = 0; //root是单源最短路的源
	pq.push(MP(0, root));
	while (!pq.empty())
	{
		PII tmp = pq.top();
		pq.pop();
		if (vis[tmp.second])
		{
			continue;
		}
		vis[tmp.second] = 1;
		for (int j = head[tmp.second]; j; j = e[j].next)
		{
			int v = e[j].to, w = e[j].val;
			if (dist[v] > dist[tmp.second] + w)
			{
				dist[v] = dist[tmp.second] + w;
				pq.push(MP(dist[v], v));
			}
		}
	}
}

int main()
{
	cin >> N >> M >> Q;
	for (int i = 1; i <= N; i++)
	{
		for (int j = 1; j <= M; j++)
		{
			cin >> num[i][j];
		}
	}

	build_graph();
	while (Q--)
	{
		int ex, ey, sx, sy, tx, ty;
		cin >> ex >> ey >> sx >> sy >> tx >> ty;
		int ans = 1e9 + 7;

		/*特判起终同位、起终点不合法等情况*/
		if (sx == tx && sy == ty)
		{
			cout << 0 << endl;
			continue;
		}
		if (!num[sx][sy] || !num[tx][ty])
		{
			cout << -1 << endl;
			continue;
		}

		for (int i = 1; i <= 4; i++)
		{
			int xx = sx + dis[i][0], yy = sy + dis[i][1];
			if (xx <= 0 || xx > N || yy <= 0 || yy > M || !num[xx][yy])
			{
				continue;
			}
			int tmp = bfs(ex, ey, xx, yy, sx, sy);
			//先把空格移到起始位置周围

			if (tmp != -1)
			{
				root = idx(sx, sy, i);
				dij();
				for (int j = 1; j <= 4; j++)
				{
					ans = min(ans, tmp + dist[idx(tx, ty, i)]);
					//取终点周围的空格位置中的最小值
				}
			}
		}
		if (ans == 1e9 + 7)
		{
			cout << -1 << endl;
			continue;
		}
		cout << ans << endl;
	}
}

/*

solve:

1.用bfs求出每个点的某个方向,到另一个方向的距离

2.将这一方向的状态与另一方向的状态之间连边,权值为距离

3.将上、下、左、右交换的状态连边

(以上状态都需合法)

4.特判起终重合、起终在非法点情况

5.对于每次询问,先用bfs把空格移到起点周围,将起点周围的情况入队

6.跑最短路

7.回答询问

图上状态表示起始点在x,y,空格在k方向

*/

好人一生平安。

2020/11/24 19:24
加载中...