传送门
题意:学生们去站点工作吧,从1出发,n-1个站点,每个站点都有学生,最后回到学校,给你很多路径,问最少车费。
思路:可以看作n-1个学生,分别去n-1个站点,最后再回到学校吧。然后答案就是1到n-1个点的最短路的和加上n-1个点到1的最短路的和。
前面的很简单,以1为起点求单源最短路就能求出1到n-1个站点的最短路和。
至于后者,由于n很大,路也很多,以每个点为起点求到1的最短路显然不现实,然后想想它们的终点都是1,于是可以选择从1出发,按逆向路求出到n-1个点的最短路即可。
吐槽:最后答案要long long 范围。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define maxn 1<<30 using namespace std; int t,m,n; int fst1[1000005],next1[1000005],node1[1000005],en1; int fst2[1000005],next2[1000005],node2[1000005],en2; int l1[1000005],d1[1000005],l2[1000005],d2[1000005]; long long int ans; bool in[1000005]; void init() { int u,v,l; en1=0; en2=0; memset(fst1,-1,sizeof(fst1)); memset(fst2,-1,sizeof(fst2)); scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&l); next1[++en1]=fst1[u]; fst1[u]=en1; node1[en1]=v; l1[en1]=l; next2[++en2]=fst2[v]; fst2[v]=en2; node2[en2]=u; l2[en2]=l; } } void spfa1(int s) { int u,v; for(int i=1;i<=n;i++)d1[i]=maxn; d1[s]=0; queue<int>q; memset(in,0,sizeof(in)); q.push(s); in[s]=1; while(!q.empty()) { u=q.front(); q.pop(); in[u]=0; for(int i=fst1[u];i!=-1;i=next1[i]) { v=node1[i]; if(d1[v]>d1[u]+l1[i]) { d1[v]=d1[u]+l1[i]; if(!in[v]) { q.push(v); in[v]=1; } } } } } void spfa2(int s) { int u,v; for(int i=1;i<=n;i++)d2[i]=maxn; d2[s]=0; queue<int>q; memset(in,0,sizeof(in)); q.push(s); in[s]=1; while(!q.empty()) { u=q.front(); q.pop(); in[u]=0; for(int i=fst2[u];i!=-1;i=next2[i]) { v=node2[i]; if(d2[v]>d2[u]+l2[i]) { d2[v]=d2[u]+l2[i]; if(!in[v]) { q.push(v); in[v]=1; } } } } } void solve() { spfa1(1); spfa2(1); ans=0; for(int i=2;i<=n;i++) { ans+=d1[i]+d2[i]; } printf("%lld\n",ans); } int main() { scanf("%d",&t); while(t--) { init(); solve(); } return 0; }