洛谷 P1342 请柬 最短路+Dijkstra算法

题面

题目链接

P1342 请柬

题目描述

在电视时代,没有多少人观看戏剧表演。Malidinesia古董喜剧演员意识到这一事实,他们想宣传剧院,尤其是古色古香的喜剧片。他们已经打印请帖和所有必要的信息和计划。许多学生被雇来分发这些请柬。每个学生志愿者被指定一个确切的公共汽车站,他或她将留在那里一整天,邀请人们参与。

这里的公交系统是非常特殊的:所有的线路都是单向的,连接两个站点。公共汽车离开起始点,到达目的地之后又空车返回起始点。学生每天早上从总部出发,乘公交车到一个预定的站点邀请乘客。每个站点都被安排了一名学生。在一天结束的时候,所有的学生都回到总部。现在需要知道的是,学生所需的公交费用的总和最小是多少。

输入输出格式

输入格式

第1行有两个整数n、m(1<=n,m<=1000000),n是站点的个数,m是线路的个数。

然后有m行,每行描述一个线路,包括3个整数,起始点,目的地和价格。

总部在第1个站点,价钱都是整数,且小于1000000000。

输出格式

输出一行,表示最小费用。

输入输出样例

输入样例

4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50

输出样例

210

说明

【时空限制】

1000ms,128M

思路

其实这一题就是求1到所有点最短路之和所有点到1的最短路之和的和(因为是有向边,所以这当然是不相等的啦)

前面一项好求,就是单源最短路径。后面一项可以稍微变化一下,我们可以把边反着建,即把u和v对调,再跑从1开始的单源最短路径,这就是所有点到1的最短路的之和了

AC代码

#include<bits/stdc++.h>
const int maxn=1000010;
using namespace std;

int n,m,tot;
int t1[maxn],n1[maxn],h1[maxn],len[maxn];
int t2[maxn],n2[maxn],h2[maxn];
long long d1[maxn],d2[maxn],ans;
bool b1[maxn],b2[maxn];
priority_queue< pair<long long,int> > q1,q2;

void dijkstra1()
{
    q1.push(make_pair(0,1));
    while(!q1.empty())
    {
        int u=q1.top().second;q1.pop();
        if(b1[u]) continue;
        b1[u]=true;
        for(int i=h1[u];i;i=n1[i])
        {
            int v=t1[i];
            if(d1[v]>d1[u]+len[i])
            {
                d1[v]=d1[u]+len[i];
                q1.push(make_pair(-d1[v],v));
            }
        }
    }
    for(int i=2;i<=n;i++) ans+=d1[i];
}

void dijkstra2()
{
    q2.push(make_pair(0,1));
    while(!q2.empty())
    {
        int u=q2.top().second;q2.pop();
        if(b2[u]) continue;
        b2[u]=true;
        for(int i=h2[u];i;i=n2[i])
        {
            int v=t2[i];
            if(d2[v]>d2[u]+len[i])
            {
                d2[v]=d2[u]+len[i];
                q2.push(make_pair(-d2[v],v));
            }
        }
    }
    for(int i=2;i<=n;i++) ans+=d2[i];
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        t1[i]=v;n1[i]=h1[u];h1[u]=i;len[i]=w;
        t2[i]=u;n2[i]=h2[v];h2[v]=i;
    }
    for(int i=2;i<=n;i++) d1[i]=d2[i]=LLONG_MAX/2;
    dijkstra1();
    dijkstra2();
    printf("%lld",ans);
    return 0;
}

总结

反向建边经常用到,灵性啊

posted @ 2018-10-08 16:04  Mercury04  阅读(323)  评论(0编辑  收藏  举报