P1629 邮递员送信
题目链接-P1629 邮递员送信
解题思路
堆
优
化
d
i
j
k
s
t
r
a
堆优化dijkstra
堆优化dijkstra
- 很明显这道题是单源最短路问题,但是这道题要求往返最短路径,且每次只能携带一个信件,所以需要跑正反两遍最短路
- 因为是有向图,所以要想反过来跑还需反向建边,反向图中源到顶点的最短路径即原图中顶点到源的最短路径
- 可以把数组开成二维的,表示正反两个不同状态,剩下的套板子就可以了( ̄▽ ̄)*
- 具体操作见代码
附上代码
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define lowbit(x) (x &(-x))
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f;
const int dir[4][2]={-1,0,1,0,0,-1,0,1};
const double PI=acos(-1.0);
const double e=exp(1.0);
const double eps=1e-10;
const int M=2e5+10;
const int N=1010;
typedef long long ll;
typedef pair<int,int> PII;
typedef unsigned long long ull;
int ne[2][M],head[2][M],to[2][M],val[2][M];
int dis[N][2],cnt,ans,n,m;
bool vis[N][2];
void add(int f,int u,int v,int w){//前向星建边
cnt++;
to[f][cnt]=v;
ne[f][cnt]=head[f][u];
val[f][cnt]=w;
head[f][u]=cnt;
}
void dij(int f,int x){//堆优化最短路
dis[x][f]=0;
priority_queue<pair<int,int> > q;
q.push(make_pair(0,x));
while(!q.empty()){
int u=q.top().second;
q.pop();
if(vis[u][f]) continue;
vis[u][f]=true;
for(int i=head[f][u];i;i=ne[f][i]){
int v=to[f][i];
if(dis[v][f]>dis[u][f]+val[f][i]){
dis[v][f]=dis[u][f]+val[f][i];
q.push(make_pair(-dis[v][f],v));
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
while(m--){
int u,v,w;
cin>>u>>v>>w;
add(0,u,v,w);//正向建边
add(1,v,u,w);//反向建边
}
memset(dis,INF,sizeof dis);
dij(0,1);//正向跑一次
dij(1,1);//反向跑一次
for(int i=1;i<=n;i++)
ans+=dis[i][0]+dis[i][1];
cout<<ans<<endl;
return 0;
}