洛谷 P5195 【[USACO05DEC]Knights of Ni S】

分层图题解很少啊,来个分层图哒


这道题一开始看,我是想的跑两次最短路,一次从起点跑,一次从终点跑,然后枚举每一个灌木,但是因为起点的时候不能走骑士,所以会\(WA\),只有\(60\)分。正解分层图最短路,在找到灌木的时候,向骑士那一层连一条边即可,从起点跑一遍最短路即可。

这里用的\(SPFA\) SPFA没有SPFA!!!:

#include <bits/stdc++.h>
using namespace std;
int n , m , s , tot , p;
int a[1010][1010]  , dis[2000010] , vis[2000010];
vector<int> e[2000010];
int id(int x , int y){	//二维压一维 
	return (x - 1) * m + y;
}
void add(int x , int y){
	e[x].push_back(y);
}
void spfa(int k){
	memset(dis , 127 , sizeof(dis));
	memset(vis , 0 , sizeof(vis));
	queue<int> q;
	vis[k] = 1;
	dis[k] = 0;
	q.push(k);
	while(!q.empty()){
		int x = q.front();
		q.pop();
		vis[x] = 1;
		for(int i = 0; i < e[x].size(); i++){
			int nx = e[x][i];
			if(dis[nx] > dis[x] + 1){
				dis[nx] = dis[x] + 1;
				if(!vis[nx]){
					vis[nx] = 1;
					q.push(nx);
				}
			}
		}
	}
}
int main(){
	cin >> m >> n;
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			cin >> a[i][j];
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++){
			if(a[i][j] == 1) continue;
			if(a[i][j] == 2) s = id(i , j);
			if(a[i][j] == 3) p = id(i , j);
			if(a[i][j] == 4) add(id(i , j) , id(i , j) + n * m);
			if((a[i - 1][j] == 0 || a[i - 1][j] == 2 || a[i - 1][j] == 4) && i != 1) add(id(i , j) , id(i - 1 , j));
			if((a[i + 1][j] == 0 || a[i + 1][j] == 2 || a[i + 1][j] == 4) && i != n) add(id(i , j) , id(i + 1 , j));
			if((a[i][j - 1] == 0 || a[i][j - 1] == 2 || a[i][j - 1] == 4) && j != 1) add(id(i , j) , id(i , j - 1));
			if((a[i][j + 1] == 0 || a[i][j + 1] == 2 || a[i][j + 1] == 4) && j != m) add(id(i , j) , id(i , j + 1));
			if((a[i - 1][j] == 0 || a[i - 1][j] == 2 || a[i - 1][j] == 4 || a[i - 1][j] == 3) && i != 1) add(id(i , j) + n * m , id(i - 1 , j) + n * m);	//向上一层连边 
			if((a[i + 1][j] == 0 || a[i + 1][j] == 2 || a[i + 1][j] == 4 || a[i + 1][j] == 3) && i != n) add(id(i , j) + n * m , id(i + 1 , j) + n * m);
			if((a[i][j - 1] == 0 || a[i][j - 1] == 2 || a[i][j - 1] == 4 || a[i][j - 1] == 3) && j != 1) add(id(i , j) + n * m , id(i , j - 1) + n * m);
			if((a[i][j + 1] == 0 || a[i][j + 1] == 2 || a[i][j + 1] == 4 || a[i][j + 1] == 3) && j != m) add(id(i , j) + n * m , id(i , j + 1) + n * m);
		}
	spfa(s);
	cout << dis[p + n * m] - 1;	//走向上一层的时候,花费了一天,减去 
	return 0;
}
posted @ 2020-09-27 17:54  那一条变阻器  阅读(137)  评论(0编辑  收藏  举报