P1342 请柬 建反图+dijkstra
一句话题意:喊你求出从1出发到所有点的最短路以及所有点的最短路到1的最短路之和。
从1开始跑最短路很容易,直接一遍堆优化dijkstra就完了。
对于其他点到1的最短路又怎么求,不可能一个一个的求,所以想到之前暑假讲关于图论的技巧——建反图。
这样的话问题就迎刃而解了,再在反图上从1开始跑一遍最短路就完了。
代码如下:
#include<bits/stdc++.h> using namespace std; const int maxn=2e6+7; const int inf=0x7fffffff; struct node1{ int nxt,to,val; }edge1[maxn*3]; struct node2{ int nxt,to,val; }edge2[maxn*3]; priority_queue<pair<long long ,int > >q1; priority_queue<pair<long long ,int > >q2; long long dis1[maxn],dis2[maxn]; int cnt1,cnt2; int n,m; int x,y,v; int head1[maxn],head2[maxn]; void add1(int x,int y,int v){ edge1[++cnt1].nxt=head1[x]; edge1[cnt1].to=y; edge1[cnt1].val=v; head1[x]=cnt1; } void add2(int x,int y,int v){ edge2[++cnt2].nxt=head2[x]; edge2[cnt2].to=y; edge2[cnt2].val=v; head2[x]=cnt2; } bool vis1[maxn]; long long ans1; void dijkstra1(int x){ for(int i=1;i<=n;i++){ dis1[i]=inf; vis1[i]=false; } dis1[x]=0; q1.push(make_pair(0,x)); while(q1.size()){ int u=q1.top().second; q1.pop(); if(vis1[u]) continue; vis1[u]=true; for(int i=head1[u];i;i=edge1[i].nxt){ int v=edge1[i].to; if(dis1[v]>dis1[u]+edge1[i].val){ dis1[v]=dis1[u]+edge1[i].val; q1.push(make_pair(-dis1[v],v)); } } } for(int i=1;i<=n;i++) ans1+=dis1[i]; } long long ans2; bool vis2[maxn]; void dijkstra2(int x){ for(int i=1;i<=n;i++){ vis2[i]=false; dis2[i]=inf; } dis2[x]=0; q2.push(make_pair(0,x)); while(q2.size()!=0){ int u=q2.top().second; q2.pop(); if(vis2[u]) continue; for(int i=head2[u];i;i=edge2[i].nxt){ int v=edge2[i].to; if(dis2[v]>dis2[u]+edge2[i].val){ dis2[v]=dis2[u]+edge2[i].val; q2.push(make_pair(-dis2[v],v)); } } } for(int i=1;i<=n;i++) ans2+=dis2[i]; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&v); add1(x,y,v); add2(y,x,v); } dijkstra1(1); dijkstra2(1); long long final=ans1+ans2; printf("%lld\n",final); return 0; }