JZOJ 6286 走格子 【bfs】【最短路】

題目大意:

給出一個n×mn\times m的矩陣,由 . # C F'.'、\ '\#'、\ 'C'、\ 'F' 組成
.'.'表示空地
#'\#'表示牆(保證圖的四邊爲牆)
CF'C'、'F'各表示一個人
C要走到F那個格子,C有兩種移動方式:
1.往上下左右任意方向移動一格(不能爲牆) 耗時爲1
2.在相鄰的牆放一個傳送門,可以往四周最近的牆放一道傳送門(可以不相鄰,面向C,放傳送門不耗時間),整個圖最多存在兩個傳送門,如果多於三道則最先放的一道門會消失,然後通過傳送門移動耗時爲1

解題思路:

C、F先記錄位置然後當做空地
廣搜找任意一個空地與距離這個點最近的牆之間的距離
然後建邊跑一遍最短路就可以了

Accepted code:Accepted\ code:

#include<queue>
#include<cstdio>
#include<cstring>
#define g(x, y) (node){x, y}
#define id(x, y) (((x)-1) * m + (y))

using namespace std;

const int N = 505;
const int inf = 1e9;

struct node {
	int x, y;
};
struct line {
	int to, z, next;
}e[N*N<<3];

int n, m, s, t, cnt;
int v[N*N], dis[N*N], len[N][N], last[N*N<<3];
int up[N][N], left[N][N], down[N][N], right[N][N];
char a[N][N];

queue <node> q;

void check(int x, int y, int L) {
	if (a[x][y] == '.' && !len[x][y])
		len[x][y] = L, q.push(g(x, y));
}

void bfs() {
	while (q.size()) {
		int x = q.front().x;
		int y = q.front().y;
		q.pop();
		check(x - 1, y, len[x][y] + 1);
		check(x, y - 1, len[x][y] + 1);
		check(x + 1, y, len[x][y] + 1);
		check(x, y + 1, len[x][y] + 1);
	}
}

void find() {
	for (int i = 1, i1 = n; i <= n; ++i, --i1)
		for (int j = 1, j1 = m; j <= m; ++j, --j1) {
			if (a[i][j] == '.') {
				if (a[i-1][j] == '#') //上 
					up[i][j] = id(i, j);
				else up[i][j] = up[i-1][j];
				
				if (a[i][j-1] == '#') //左 
					left[i][j] = id(i, j);
				else left[i][j] = left[i][j-1];
			}
			if (a[i1][j1] == '.') {
				if (a[i1+1][j1] == '#') //下 
					down[i1][j1] = id(i1, j1);
				else down[i1][j1] = down[i1+1][j1];
				
				if (a[i1][j1+1] == '#') //右  
					right[i1][j1] = id(i1, j1);
				else right[i1][j1] = right[i1][j1+1];
			}
		}
}

void add(int x, int y, int w) {
	e[++cnt] = (line){y, w, last[x]}; last[x] = cnt;
}

void addL(int x, int y, int w) {
	add(x, y, w); add(y, x, w);
}

void addline() {
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			if (a[i][j] == '.') {
				if (a[i][j+1] == '.') addL(id(i, j), id(i, j+1), 1);
				if (a[i+1][j] == '.') addL(id(i, j), id(i+1, j), 1);
				if (up[i][j] != id(i, j)) add(id(i, j), up[i][j], len[i][j]);
				if (down[i][j] != id(i, j)) add(id(i, j), down[i][j], len[i][j]);
				if (left[i][j] != id(i, j)) add(id(i, j), left[i][j], len[i][j]);
				if (right[i][j] != id(i, j)) add(id(i, j), right[i][j], len[i][j]);
			}
}

void Spfa() {
	memset(dis, 127 / 3, sizeof dis);
	memset(v, 0, sizeof v);
	dis[s] = 0; v[s] = 1;
	queue <int> que;
	que.push(s);
	while (que.size()) {
		int x = que.front(); v[x] = 0; que.pop();
		for (int i = last[x]; i; i = e[i].next) {
			int y = e[i].to;
			if (dis[y] > dis[x] + e[i].z) {
				dis[y] = dis[x] + e[i].z;
				if (!v[y]) {
					que.push(y);
					v[y] = 1;
				}
			}
		}
	}
}

int main() {
    scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++i)
		scanf("%s", a[i] + 1);
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j) {
			if (a[i][j] == 'C') s = id(i, j), a[i][j] = '.';
			if (a[i][j] == 'F') t = id(i, j), a[i][j] = '.';
		}
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			if (a[i][j] == '#') q.push(g(i, j));
	bfs(), find(), addline(), Spfa();
	if (dis[t] >= inf) puts("no"); else printf("%d", dis[t]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章