Description
随着中国经济的腾飞,中国的物流产业迎来了发展的春天。特别是在上海这样一个拥有广阔国内腹地的国际化大都市,物流业以空前的速度膨胀。
当然是大蛋糕就会吸引许多馋嘴猫,馋嘴猫多了就会有残酷的竞争。当大量资金流入物流产业时,KOP 集团为了稳坐在国内物流业的第一把交椅,决定对现行的运输方案进行改良,以减少自己的成本同时使其它竞争者知难而退。
作为世界100强的KOP集团当然知道要找到最优运输方案,肯定得靠数学和算法很好的软件工程师,于是他们理所当然地找到华东师范大学软件学院。决定通过赞助一场程序比赛来找出最优秀的工程师( ACM : Ace Coding Man )。
比赛只有一道题目,是运输线路的简单抽象,题意如下:
SH 市有N个运输中转点(简单标示为 1,2,3,....,N),中转点之间可能有一条运输线路,这条线路有一个特殊的地方就是从A 到B点需要耗费 c1 个单位的查克拉(SH市的货币单位),但从B到A可能需要 c2 个查克拉。当然c1不一定等于c2,也能从A到B之后就不能从B返回A了。你可以理解为这些线路是“单向”的。线路总共有 M 条。每天有N-1辆车从KOP集团总部(这里假设就是标号为1的中转点),出发,分别发往N-1个剩下的中转点,然后当天再从所到达的中转点返回。你的任务就是要求出一天的最小耗费。
Input
第一行为 C ,表示有C个测试用列。接下来分别为C个测试用列。
每个测试用例的格式如下:
第一行为两个整数,N,M ,分别表示有N个中转点和M条道路。( 1=< N, M <=1000000 .);
紧接着的M 行每行有三个值 A B c; 分别表示从中转点A到中转点B需要耗费 c 个单位的查克拉。 ( 0<= c <= 1000000000 ).
Output
你的输出应该包括C行,每行输出一个值,对应于相应的用列的最少耗费。
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
46
210
题解:先把1到各个点的最小距离和求出来。对于所有点到1的最小距离之和,我们可以将两个点的距离反转,即u->v的cost变成v->u的cost,这样,其他所有点到1的最短距离之和就是1到其他点的最小距离之和了,复杂度从n2logn变成了nlongn.足以通过。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int INF = 0x3fffffff;
struct Node
{
int to;
int cost;
Node(){}
Node(int a,int b)
{
to = a;
cost = b;
}
bool operator< (Node t) const
{
return cost > t.cost;
}
};
vector<Node> vec[2][1000006];
long long d[2][1000006];
bool visited[1000006];
void djistra(int n,int s,int w)
{
memset(visited,false,sizeof(visited));
for(int i = 1;i <= n;i++) //一开始所有点不相邻
{
d[w][i] = INF;
}
priority_queue<Node> q;
q.push(Node(1,0)); //将起点入队
d[w][s] = 0; //自己到自己的距离为0
for(int i = 1;i < n;i++) //找出n - 1条边
{
while(!q.empty()) //每次找一条到起点的最小边
{
Node p = q.top();
q.pop();
if(!visited[p.to]) //队列中的最小边没有访问过
{
visited[p.to] = true; //访问了
for(int j = 0;j < vec[w][p.to].size();j++) //更新找到的最小边到其他点的距离
{
int k = vec[w][p.to][j].to;
if(!visited[k] && d[w][k] > d[w][p.to] + vec[w][p.to][j].cost)
{//如果该点到原点的距离+相邻点的距离大于邻接点到原点的距离,则更新该点最小距离并且入队
//入队之后找找到距离原点最近的点开始更新
d[w][k] = d[w][p.to] + vec[w][p.to][j].cost; //更新邻接点的最小距离
q.push(Node(k,d[w][k])); //压入更新的距离,因为此点可能是距离原点最近的
}
}
break;
}
}
}
}
int main()
{
int T;
cin>>T;
int n,m;
while(T--)
{
scanf("%d%d",&n,&m);
int u,v,c;
for(int i = 0;i < m;i++)
{
scanf("%d%d%d",&u,&v,&c);
vec[0][u].push_back(Node(v,c)); //反转,将u->v的花费变成v->u的花费,
vec[1][v].push_back(Node(u,c));
}
djistra(n,1,0);
djistra(n,1,1);
long long ans = 0;
for(int i = 2;i <= n;i++)
{
ans += d[0][i] + d[1][i]; //将两次最短距离加上
}
cout<<ans<<endl;
for(int i = 1;i <= n;i++)
{
vec[0][i].clear();
vec[1][i].clear();
}
}
return 0;
}