問題描述
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。輸入保證每個城市都可以通過鐵路達到首都。
解題思路
一、單源最短路徑問題
二、使用spfa算法解決
三、思想:
1. 使用鄰接表存儲圖;
2. 將所有結點到源結點的距離初始化爲無窮【dis】,到前一個結點的距離爲無窮【pre】,是否在隊列中初始化爲不在隊列【vis】;
3. 源結點入隊,到自身距離爲0;
4. 對隊首元素重複操作:彈出隊首元素,遍歷其連接的點,對每條邊進行鬆弛操作,若鬆弛成功且不在隊列中,入隊。鬆弛成功的鄰接結點到前一個結點的距離更新爲邊權。直到隊列爲空。
5. 此時從第二個結點開始的各pre值相加即得最短路徑總長度。
/*
1.求出所有結點到結點1的最短路程
2.求最短路程時記錄每個節點的最短前驅
*/
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<fstream>
#define INF 1000000000
#define N 100005
using namespace std;
struct Node{
int to; //到達的結點
int next; //同一起點的下一條邊
int w; //路徑長度(邊權)
};
int n, m; //結點,邊數量
int head[N]; //Head[u] = t1 意爲從弧頭 u 出發 可以到達點 t1
int dis[N]; //距離向量,源點的最短距離
int pre[N]; //前驅結點
bool vis[N]; //是否在隊列中
Node map[N*10]; //鄰接表
queue <int> q;
int ip = 0;
void add( int a, int b, int c ){
map[ip].to = b; //後繼結點
map[ip].w = c; //邊權
map[ip].next = head[a];//相當於鄰接表中把next指針指向後繼邊表結點
head[a] = ip++; //相當於鏈表頭指針指向新地址
}
void spfa( int s ){
memset( vis, 0, sizeof(vis) );
for( int i = 0; i <= n; i++ ){
dis[i] = INF;
pre[i] = INF;
}
q.push( s );
dis[s] = 0; //到其自身路徑爲0
while( !q.empty() ){
int u = q.front();
q.pop();
vis[u] = 0;
for( int i = head[u]; i != -1; i = map[i].next ){
int v = map[i].to;
int w = map[i].w;
if( dis[v] > dis[u] + w ){
dis[v] = dis[u] + w;
pre[v] = w;
if( !vis[v] ){ //若不在隊列中,入隊
vis[v] = 1;
q.push(v);
}
}
else if( dis[v] == dis[u] + w ){
pre[v] = min( pre[v], w );
}
}
}
}
int main(){
int ans = 0;
int a, b, c;
memset( head, -1, sizeof(head) );
// ifstream fin("00.txt", ios::in);
// fin >> n >> m;
cin >> n >> m;
for( int i = 0; i < m; i++ ){
// fin >> a >> b >> c;
cin >> a >> b >> c;
add( a, b, c);
add( b, a, c);
}
spfa( 1 );
for( int i = 2; i <= n; i++ ){
ans += pre[i];
}
cout << ans;
return 0;
}