CCF201609-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。輸入保證每個城市都可以通過鐵路達到首都。

解題思路

一、單源最短路徑問題
二、使用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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章