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

POJ-1511 Invitation Cards (单源最短路+逆向)

时间:2018-08-28 01:06:55      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:--   ble   iostream   不可   return   分析   string   疑问   ref   

<题目链接>

题目大意:

有向图,求从起点1到每个点的最短路然后再回到起点1的最短路之和。

解题分析:

在求每个点到1点的最短路径时,如果仅仅只是遍历每个点,对它们每一个都进行一次最短路算法,那么即使是用了堆优化的dijkstra,时间复杂度也高达O(n^2 logn),而本题有1000000个点,毫无疑问,这种想法必然是不可行的,所以我们可以采用逆向思维,将图中的每一条有向边全部反向,然后以1为起点,仅做一次dijkstra,就能得到1到所有点的最短距离,即反向前的,所有点到1点的最短距离。所以,本题的正解应为:先以1为起点,做一次dijkstra,算出,1到所有点的最短距离,然后将边反向,再以1为起点,做一次dijkstra,此时就能得到,其他所有点到1的最短距离,将所有的最短距离相加,即为答案。时间复杂度为O(nlogn)。

 

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;

#define INF 0x3f3f3f3f
const int maxn =1000000+100;

int n,m;
struct Edge{
    int to;
    int next;
    int w;
};

Edge edge[maxn],redge[maxn];

struct NODE{
    int index;
    int dis;
    bool operator < (NODE const &tmp)const{
        return dis>tmp.dis;
    }
}d[maxn];

int dist[maxn];   
int cnt,rcnt,head1[maxn],head2[maxn],vis[maxn];

void init(){
    memset(head1,-1,sizeof(head1));
    memset(head2,-1,sizeof(head2));
    cnt=0,rcnt=0;
}

void add1(int u,int v,int w){
    edge[cnt].to=v;edge[cnt].w=w;
    edge[cnt].next=head1[u];
    head1[u]=cnt++;
}

void add2(int u,int v,int w){
    redge[rcnt].to=v;redge[rcnt].w=w;
    redge[rcnt].next=head2[u];
    head2[u]=rcnt++;
}

void dijkstra1(int st){           
    for(int i=1;i<=n;i++){
        vis[i]=0;d[i].dis=INF,d[i].index=i;
    }

    priority_queue<NODE>q;
    d[st].dis=0;q.push(d[st]);
    while(!q.empty()){
        int u=q.top().index;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=head1[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(d[v].dis>d[u].dis+edge[i].w){
                d[v].dis=d[u].dis+edge[i].w;
                q.push(d[v]);
            }
        }
    }
}

void dijkstra2(int st){           //因为正、反向边的edge[],和head[]散组不同,所以要将另外再写一个dijkstra函数
    for(int i=1;i<=n;i++){
        vis[i]=0;d[i].dis=INF,d[i].index=i;
    }

    priority_queue<NODE>q;
    d[st].dis=0;q.push(d[st]);
    while(!q.empty()){
        int u=q.top().index;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        for(int i=head2[u];i!=-1;i=redge[i].next){
            int v=redge[i].to;
            if(d[v].dis>d[u].dis+redge[i].w){
                d[v].dis=d[u].dis+redge[i].w;
                q.push(d[v]);
            }
        }
    }
}

int main(){
    int t;scanf("%d",&t);
    while(t--){
        scanf("%d %d",&n,&m);
        init();
        for(int i=1;i<=m;i++){
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            add1(a,b,c);          //存储该有向图正确的边
            add2(b,a,c);          //将该有向图的所有边反向存储
        }

        long long sum=0;

        dijkstra1(1);        //边未反向之前,求出1到所有点的最短路
        for(int i=2;i<=n;i++){
            sum+=d[i].dis;
        }

        dijkstra2(1);       //将边反向后,求出所有点到1点的最短路
        for(int i=2;i<=n;i++){
            sum+=d[i].dis;
        }
        printf("%lld\n",sum);
    }
    return 0;
}

 

 

2018-08-27

POJ-1511 Invitation Cards (单源最短路+逆向)

标签:--   ble   iostream   不可   return   分析   string   疑问   ref   

原文地址:https://www.cnblogs.com/00isok/p/9545360.html

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