洛谷 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;
}