POJ - 1511 - 两次SPFA
这道题也算是一道模板题,但是第一次用优先队列迪杰斯特拉就T了。1e6的数据量,给了8s,网上其他题解中说要用SPFA。
题意:N个点的带权有向图。每次都从1出发,要到达其余没有被访问过的一个点(发传单?),然后返回,过程中其余被访问的点不计算在内。求整个过程走过的最短路程。
分析:用原图跑SPFA计算从源点1到其余各点的最短路,再将原图转置为反向图,对反向图再跑一遍SPFA,计算出各点到1的最短路(求各点到一个点的最短路是这么个操作)。
然后求sigma(d[i]+rd[i])。
#include<iostream> #include<cstring> #include<stdio.h> #include<map> #include<string> #include<algorithm> #include<queue> //#define LOCAL using namespace std; typedef long long LL; const LL INF =(1ll<<60); const int maxn =1e6+5; struct Edge{ int to,next; LL val; }; struct SPFA{ int head[maxn]; Edge edges[maxn]; LL d[maxn]; bool inq[maxn]; int n,tot; void init(int n){ this->tot=0; this->n = n; memset(head,-1,sizeof(head)); } void AddEdge(int u,int v,LL val){ edges[tot].to = v; edges[tot].val = val; edges[tot].next = head[u]; head[u] = tot++; } void spfa(int s){ for(int i=0;i<=n;++i){ inq[i]=false; d[i] = INF; } queue<int> Q; Q.push(s); d[s]=0; inq[s] = true; while(!Q.empty()){ int x = Q.front();Q.pop(); inq[x] =false; for(int i = head[x];~i;i=edges[i].next){ int v = edges[i].to; if(d[v]>d[x]+edges[i].val){ d[v] = d[x]+edges[i].val; if(!inq[v]){ Q.push(v); inq[v] = true; } } } } } }G,rG; int main() { #ifdef LOCAL freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int N,M,u,v; LL tmp; int T; scanf("%d",&T); while(T--){ scanf("%d%d",&N,&M); G.init(N); rG.init(N); for(int i=1;i<=M;++i){ scanf("%d%d%lld",&u,&v,&tmp); G.AddEdge(u,v,tmp); rG.AddEdge(v,u,tmp); } G.spfa(1); rG.spfa(1); LL res=0; for(int i=2;i<=N;++i){ res+=G.d[i]+rG.d[i]; } printf("%lld\n",res); } return 0; }
为了更好的明天