POJ - 1511 - 两次SPFA

Posted xiuwenli

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
",res);
    }
    return 0;
}

 

以上是关于POJ - 1511 - 两次SPFA的主要内容,如果未能解决你的问题,请参考以下文章

POJ1511 Invitation Cards —— 最短路spfa

POJ 1511 Invitation Cards(逆向思维 SPFA)

POJ 1511 链式前向星+SPFA

Invitation Cards POJ - 1511 spfa

Invitation Cards POJ 1511 SPFA || dij + heap

POJ 1511 最短路spfa