问题描述
在电视时代,很少有人去剧院演出。马里迪内西亚的古代喜剧演员们知道这个事实。他们想要宣传戏剧,尤其是古典喜剧。他们印制了载有所有必要资料和节目的邀请卡。许多学生被雇来把这些请帖分发给人们。每个学生志愿者都指定了一个公交车站,他或她会在那里呆上一整天,邀请人们乘坐公交车。他们开设了一门特殊的课程,让学生们学习如何影响他人,以及影响与抢劫之间的区别。
交通系统非常特殊:所有线路都是单向的,而且恰好连接两个站点。每半小时有一辆公共汽车从始发站开出。到达目的地站后,它们返回空的起始站,在那里它们等待到下一个完整的半小时,例如X:00或X:30,其中“X”表示时间。两站之间的交通费由专用表格支付,并在现场支付。这些线路的规划是这样的,每次往返(即在同一站出发和结束的旅程)都要经过一个中央检查站(CCS),在那里每位乘客必须通过包括身体扫描在内的全面检查。
所有的ACM学生成员每天早上离开CCS。每位志愿者都要在预定的一站下车,邀请乘客。志愿者和车站一样多。最后,所有的学生都回到CCS。你要编写一个电脑程序,帮助ACM将每天运送员工的费用降到最低。
输入
输入由N种情况组成。输入的第一行只包含正整数n。每种情况都以一行开始,其中恰好包含两个整数P和Q, 1 <= P,Q <= 1000000。P为包括CCS在内的站点数,Q为公交线路数。然后是Q线,每条线描述一条总线。每一行都包含三个数字——起始站、目的地站和价格。CCS是由1号指定的。价格是正整数,其和小于1000000000。你也可以假设从一站到另一站总是可能的。
输出
对于每个案例,打印一行包含ACM每天为其志愿者的旅费支付的最低金额。
Sample Input
2
2 2
1 2 13
2 1 33
4 6
1 2 10
2 1 60
1 3 20
3 4 10
2 4 5
4 1 50
Sample Output
46
210
题意:
求起点到每个点的最短距离和,加上每个点回到终点的最短距离和(有向图来回距离不一样)
分析:
从起点到其他点直接正常最短路就行了很简单
主要是回来那段,如果每个点都跑一次最短路显然不行。
巧妙的想法是把所有边起点和终点反过来,这时候从起点跑出来的最短路就相当于从其他所有点到起点的最短路。
妙啊
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<vector>
#include<cstring>
#include<queue>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int N=1e6+5;
const int M=2e6+5;
int read(){
int x=0,f=0;char c=getchar();
while(c!='-'&&!isdigit(c))c=getchar();
if(c=='-')f=1,c=getchar();
while(isdigit(c))x=x*10+c-'0',c=getchar();
return f?-x:x;
}
ll head[N],nt[M],to[M],w[M];//存正常的边
ll head2[N],nt2[M],to2[M],w2[M];//存反转之后的边
ll d[N];
bool mark[N];
int n,m,cnt,cnt2;
void init(){
memset(head,-1,sizeof head);
memset(head2,-1,sizeof head2);
cnt=cnt2=0;
}
void add(int x,int y,int z){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;
cnt2++;nt2[cnt2]=head2[y];head2[y]=cnt2;to2[cnt2]=x;w2[cnt2]=z;//建立反转的边
}
void spfa(int st){
queue<int>q;
memset(mark,0,sizeof mark);
memset(d,inf,sizeof d);
q.push(st);
mark[st]=0;
d[st]=0;
while(!q.empty()){
int x=q.front();
q.pop();
mark[x]=0;
for(int i=head[x];i!=-1;i=nt[i]){
int v=to[i];
if(d[v]>d[x]+w[i]){
d[v]=d[x]+w[i];
if(!mark[v]){
mark[v]=1;
q.push(v);
}
}
}
}
}
void spfa2(int st){
queue<int>q;
memset(mark,0,sizeof mark);
memset(d,inf,sizeof d);
q.push(st);
mark[st]=0;
d[st]=0;
while(!q.empty()){
int x=q.front();
q.pop();
mark[x]=0;
for(int i=head2[x];i!=-1;i=nt2[i]){
int v=to2[i];
if(d[v]>d[x]+w[i]){
d[v]=d[x]+w[i];
if(!mark[v]){
mark[v]=1;
q.push(v);
}
}
}
}
}
int main(){
int T=read();
while(T--){
init();
n=read(),m=read();
for(int i=0;i<m;i++){
int a=read(),b=read(),c=read();
add(a,b,c);
}
spfa(1);
ll ans=0;
for(int i=1;i<=n;i++){
ans+=d[i];
}
spfa2(1);
for(int i=1;i<=n;i++){
ans+=d[i];
}
cout<<ans<<endl;
}
return 0;
}