洛谷 P1342 请柬 最短路+Dijkstra算法
题面
题目链接
题目描述
在电视时代,没有多少人观看戏剧表演。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;
}
总结
反向建边经常用到,灵性啊