题解 P5195 【[USACO05DEC]Knights of Ni 骑士】
好像都是两遍bfs或者dfs
其实跑一遍分层图就可以了
在骑士处连接分层图,具体看代码
//Code by : Y-k-y
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#define ll long long
const int N=10000010;
using namespace std;
inline int rnd(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){res=res*10+ch-'0';ch=getchar();}
return res*f;
}
inline void wr(int x){
if(x<0){putchar('-');x=-x;}if(x>9) wr(x/10);putchar(x%10+'0');
}
int n,m,sx,sy,tot;
int a[1005][1005];
struct pp{
int v,nxt;
}edge[N];
int head[N],d[N],id[1004][1005];
bool ans[N];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
bool vis[N];
inline void add(int u,int v){
edge[++tot].nxt=head[u],head[u]=tot;
edge[tot].v=v;
}
inline int chk(int x,int y){
return x>0&&x<=n&&y>0&&y<=m&&a[x][y]!=1;
}
inline int num(int x,int y){
return (x-1)*m+y;
}
inline void spfa(){
queue<int>q;
q.push(id[sx][sy]);vis[id[sx][sy]]=1;
memset(d,0x3f,sizeof(d));
d[id[sx][sy]]=0;
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(d[v]>d[u]+1){
d[v]=d[u]+1;
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
}
}
int main(){
cin>>m>>n;//n m的顺序。。。
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
a[i][j]=rnd(),id[i][j]=num(i,j);//类似hash吧
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==1)continue;
for(int k=0;k<4;k++){
int x=i+dx[k],y=j+dy[k];
if(chk(x,y)){
add(id[i][j],id[x][y]);
add(id[i][j]+n*m,id[x][y]+n*m);//两个图上都要连边
}
}
if(a[i][j]==4){
add(id[i][j],id[i][j]+n*m);//骑士,连接两个图
}
if(a[i][j]==3){
ans[id[i][j]]=1;
}
if(a[i][j]==2){
sx=i,sy=j;
}
}
}
spfa();
int sum=1<<30;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(ans[id[i][j]]){
sum=min(sum,d[id[i][j]+n*m]);
}
}
}
wr(sum-1);//因为在跳图的时候,也算了一个距离,所以减一
return 0;
}