题意
有一个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; }