码迷,mamicode.com
首页 > 其他好文 > 详细

POJ - 1511 - 两次SPFA

时间:2018-07-14 23:38:13      阅读:324      评论:0      收藏:0      [点我收藏+]

标签:printf   turn   ring   ace   style   memset   open   namespace   迪杰斯特拉   

这道题也算是一道模板题,但是第一次用优先队列迪杰斯特拉就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;
}

 

POJ - 1511 - 两次SPFA

标签:printf   turn   ring   ace   style   memset   open   namespace   迪杰斯特拉   

原文地址:https://www.cnblogs.com/xiuwenli/p/9311220.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!