ccf 201609-4交通规划

问题描述
  G国国王来中国参观后,被中国的高速铁路深深的震撼,决定为自己的国家也建设一个高速铁路系统。
  建设高速铁路投入非常大,为了节约建设成本,G国国王决定不新建铁路,而是将已有的铁路改造成高速铁路。现在,请你为G国国王提供一个方案,将现有的一部分铁路改造成高速铁路,使得任何两个城市间都可以通过高速铁路到达,而且从所有城市乘坐高速铁路到首都的最短路程和原来一样长。请你告诉G国国王在这些条件下最少要改造多长的铁路。

输入格式
  输入的第一行包含两个整数n, m,分别表示G国城市的数量和城市间铁路的数量。所有的城市由1到n编号,首都为1号。
  接下来m行,每行三个整数a, b, c,表示城市a和城市b之间有一条长度为c的双向铁路。这条铁路不会经过a和b以外的城市。
输出格式
  输出一行,表示在满足条件的情况下最少要改造的铁路长度。
样例输入
4 5
1 2 4
1 3 5
2 3 2
2 4 3
3 4 2
样例输出
11
评测用例规模与约定
  对于20%的评测用例,1 ≤ n ≤ 10,1 ≤ m ≤ 50;
  对于50%的评测用例,1 ≤ n ≤ 100,1 ≤ m ≤ 5000;
  对于80%的评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 50000;
  对于100%的评测用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000,1 ≤ a, b ≤ n,1 ≤ c ≤ 1000。输入保证每个城市都可以通过铁路达到首都。

题目抽象

要求所有结点与源结点连通,使得所有边权之和最小。即求最小的最短路径树

邻接表存储图,即g[],是一种动态的存储

数组dist[]中存储单源(首都,结点1)到各个结点(城市)的最短距离。优先队列q按照边的权值从小到大排队,便于计算最短路径。

对于n个结点的城市,要连通起来,最少有n-1条道路就够了。

数组cost[i]用于存储要到达结点i,并且满足单源最短路径的条件,需要改造的铁路的长度。这是使用Dijkstra算法解决本问题需要增加的。程序中的72行就是增加的逻辑。

另外一个问题,从单源出发到达某个结点,最短路径有两条以上,并且路径长度相等时,需要选一个代价小的。例如,测试实例中,结点1到4有两条路径,1-2-4和1-3-4,其距离都是7,边1-2和1-3是必选的,边2-4和3-4是可选的,由于边2-4的权为3,而边3-4的权为2,所以为了到达结点4选择小的权2。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<stack>
#include <iostream>
#include <vector>
#include <queue>
#define MAX 10000
#define INF 1e6
using namespace std;
bool vis[MAX+1];
int cost[MAX+1];
int dis[MAX+1];
struct node{
int num;
int cost;
node(int nn,int cc):num(nn),cost(cc){
}
bool operator < (const node&p)const{
return cost>p.cost;
}
};
struct edge{
int v;
int cost;
edge(int vv,int cc):v(vv),cost(cc){
}
};
vector<edge> g[MAX+1];
int n;
priority_queue<node> pq;
void dij(){
for(int i=1;i<=n;i++)
{
dis[i]=INF;
cost[i]=INF;
vis[i]=false;
}
// for(int i=0;i<g[1].size();i++){
// edge e=g[1][i];
// dis[e.v]=e.cost;
// cout<<e.cost<<endl;
//
//}
dis[1]=0;
cost[1]=0;


pq.push(node(1,0));
while(!pq.empty()){
node t=pq.top();
pq.pop();
if(vis[t.num]) continue;
vis[t.num]=true;
for(int i=0;i<g[t.num].size();i++){
edge e=g[t.num][i];

if(vis[e.v]) continue;
int tmpcost=e.cost;
if(tmpcost+dis[t.num]<dis[e.v]){
dis[e.v]=tmpcost+dis[t.num];
cost[e.v]=tmpcost;
pq.push(node(e.v,dis[e.v]));
}
else if(tmpcost+dis[t.num]==dis[e.v]){
cost[e.v]=min(cost[e.v],tmpcost);
}
}


}

}
int main(){
int cases,src,u,v,w;
cin>>n>>cases;
for(int i=cases;i>0;i--){
cin>>u>>v>>w;
g[u].push_back(edge(v,w));
g[v].push_back(edge(u,w));
}


dij();
int ans=0;
for(int i=1;i<=n;i++){
ans+=cost[i];
}
cout<<ans<<endl;
}