题意
有一个n*m的地图,地图上有三个国家和一些道路(路没修就不能走),还有一些障碍,每个国家都是一个联通块,现在可以在道路上进行修路,让路可以走,现在问让三个国家联通最小需要修多少条路。
思路
对于每个国家都进行bfs,算出每个国家到每个点的最短距离。三个国家联通,枚举联通的一点即可。
所以枚举所有不是障碍的点,更新最小值,注意如果枚举的点是道路而不是国家的话,只需要有一个国家修路即可,所以要减去2.
bfs中,如果达到的坐标是".",那么修路的就需要加1,保证bfs的最优性,如果是点,就把更新的坐标放到最后,如果是国家,不需要修路,花费保持不变,就丢到队列前,所以用一个双端队列实现。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
char mp[1005][1005];
int dis[4][1005][1005];
int to[][2]{1,0,-1,0,0,-1,0,1};
bool vis[1005][1005];
bool check(int x,int y){
if(x<0 || x>=n || y<0 || y>=m || mp[x][y]=='#' || vis[x][y]) return 1;
return 0;
}
void bfs(int a){
#define pa pair<int,int>
#define x first
#define y second
deque<pa> que;
memset(vis,0,sizeof vis);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(mp[i][j]-'0'==a){
que.push_back({i,j});
dis[a][i][j]=0;
vis[i][j]=1;
}
}
}
while(!que.empty()){
pa now=que.front();
que.pop_front();
for(int i=0;i<4;i++){
int fx=now.x+to[i][0],fy=now.y+to[i][1];
if(check(fx,fy)) continue;
vis[fx][fy]=1;
int k=(mp[fx][fy]=='.');
dis[a][fx][fy]=dis[a][now.x][now.y]+k;
if(k) que.push_back({fx,fy});
else que.push_front({fx,fy});
}
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++) cin>>mp[i];
memset(dis,0x1f,sizeof dis);
bfs(1),bfs(2),bfs(3);
int ans=1e9;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(mp[i][j]!='#'){
int k=0;
if(mp[i][j]=='.') k=2;
ans=min(ans,dis[1][i][j]+dis[2][i][j]+dis[3][i][j]-k);
}
}
}
if(ans>=3*n*m) ans=-1;
cout<<ans;
return 0;
}

京公网安备 11010502036488号