枚举三条路径重合点,跑dij。预处理出三个点到每个点的最短路。因为事无向边,所以就事每个点到这三个点的最短路。
\(O(nm\log (nm))\)
另外,我的点拆边光荣的挂掉了。
不过可以方格dij。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int cnt=0,ans=0x3f3f3f3f3f3f3f3f;
const int maxn=1e3+5;
int n,m,a,b,c;
int W[maxn][maxn];
int dis[maxn][maxn],adis[maxn][maxn];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
struct node{
int x,y,w;
node(){}
node(int a,int b,int c):x(a),y(b),w(c){}
bool operator <(const node &b)const{return w>b.w;}
};
void dij(int x,int y){//方格最短路,spfa的噩梦
memset(dis,0x3f3f3f3f,sizeof(dis));
priority_queue<node> q;
q.push((node){x,y,W[x][y]});
dis[x][y]=W[x][y];
while(!q.empty()){
int nx=q.top().x,ny=q.top().y,d=q.top().w;
q.pop();
if(d!=dis[nx][ny])continue;
for(int i=0;i<4;i++){
int gx=nx+dx[i],gy=ny+dy[i];
if(gx<1||gx>n||gy<1||gy>m)continue;
if(dis[gx][gy]>dis[nx][ny]+W[gx][gy]){
dis[gx][gy]=dis[nx][ny]+W[gx][gy];
q.push((node){gx,gy,dis[gx][gy]});
}
}
}
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)adis[i][j]+=dis[i][j];
}
signed main(){
cin>>n>>m>>a>>b>>c;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>W[i][j];
dij(1,a),dij(n,b),dij(n,c);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
ans=min(ans,adis[i][j]-2*W[i][j]);
}
}
cout<<ans;
return 0;
}