题目:给定n个城市m条单向权值路,邮递员从城市1往各个城市送信,每次到达后要折回城市1取信,问求权值最小。
传送门:邮递员送信 - 洛谷;
思路:一开始以为的是双向,想直接求得最短路径和*2结束,但样例给的是个奇数,即到x城市的路线为1->a->b->x;回来的路线可能为x->s->c->1;去时是单源最短路径,回来是多源;
考虑x->s->c->1可以写成1->c->s->x;即可以进行反向存图,然后进行最短路的求值;
代码:
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define INF 0x3f3f3f3f
const int N=2e6+5;
int dis[N],fdis[N];
bool vis[N],fvis[N];
vector<pair<int,int> >mp[N],fmp[N];//加了f就是反向存图
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q,fq;
void add_adge(int a,int b,int w){
mp[a].push_back(pair<int,int>(w,b));
fmp[b].push_back(pair<int,int>(w,a));//反向存图;
}
int main(){
int n,m,ans=0;
memset(dis,INF,sizeof(dis));
memset(fdis,INF,sizeof(fdis));
cin>>n>>m;
while(m--){
int u,v,w;
cin>>u>>v>>w;
add_adge(u,v,w);
}
dis[1]=0;
fdis[1]=0;
q.push(pair<int,int>(0,1));
while(!q.empty()){
pair<int,int>f=q.top();
q.pop();
if(vis[f.second])continue;
vis[f.second]=1;
for(int i=0;i<mp[f.second].size();i++){
int v=mp[f.second][i].second;
int w=mp[f.second][i].first;
if(dis[u]>w+dis[f.second]){
dis[u]=w+dis[f.second];
q.push(pair<int,int>(dis[u],u));
}
}
}//正向单源
fq.push(pair<int,int>(0,1));
while(!fq.empty()){
pair<int,int>f=fq.top();
fq.pop();
if(fvis[f.second])continue;
fvis[f.second]=1;
for(int i=0;i<fmp[f.second].size();i++){
int v=fmp[f.second][i].second;
int w=fmp[f.second][i].first;
if(fdis[u]>w+fdis[f.second]){
fdis[u]=w+fdis[f.second];
fq.push(pair<int,int>(dis[u],u));
}
}
}//反向图跑最短路
for(int i=1;i<=n;i++){
ans+=(dis[i]+fdis[i]);
}
cout<<ans<<endl;
return 0;
}