题目大意:有一个n*m的大陆,在大陆上有三个州(1、2、3),现在需要三个州相连,求最少需要修建多少个单元格作为道路。
题记:
首先要了解一下01BFS。bfs可以O(V+E)求解边权全为1的图上的最短路,但是当边权只有0或者1时,可以使用01BFS来快速求解。
01BFS维护一个双端队列,当边权为0时,是利用push_front()放在队头,边权为1时使用push_back()放在队尾。
以每个国家的任意一格为起点,对整张图跑一遍01BFS,就得到了三个国家到所有各自的距离。最后遍历所有各自,找到三个国家与这个格子的距离之和即是答案。
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int>PII;
#define F first
#define S second
const int N=1005;
const int INF=0x3f3f3f3f;
char a[N][N];
int dis[][2]={1,0,0,1,-1,0,0,-1};
int n,m;
int dist[N][N][4];
deque<PII>q;
bool check(int x,int y,int xx){
if(x<1||x>n||y<1||y>m||a[x][y]=='#'||dist[x][y][xx]!=INF)
return false;
return true;
}
void bfs(int xx){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]==xx+'0'){
dist[i][j][xx]=0;
q.push_back(PII(i,j));
//由于放进去的都是边权为0的点,所以放队头队尾都可以
}
//将x州的坐标全部放进队列
while(!q.empty()){
PII st=q.front();
q.pop_front();
//从队头拿出一个元素
int x=st.F,y=st.S;
for(int i=0;i<4;i++){
int nx=x+dis[i][0];
int ny=y+dis[i][1];
if(check(nx,ny,xx)){
int flag=a[nx][ny]=='.';
//判断当前走到的这个格子是否为某一个州
//两个不同州格子之间边权也为0
dist[nx][ny][xx]=dist[x][y][xx]+flag;
if(flag) q.push_back(PII(nx,ny));
else q.push_front(PII(nx,ny));
}
}
}
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i]+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=3;k++)
dist[i][j][k]=INF;
//初始化三个州到每一格的距离都是无限大
bfs(1);
bfs(2);
bfs(3);
//bfs三个州
int ans=INF;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int sum=dist[i][j][1]+dist[i][j][2]+dist[i][j][3];
//cout<<sum<<endl;
if(a[i][j]=='.')sum-=2;
//由于a[i][j]这个点只需要铺一次道路,所以要减去两次
ans=min(ans,sum);
}
}
if(ans==INF) cout<<"-1"<<endl;
else cout<<ans<<endl;
return 0;
}

京公网安备 11010502036488号