CCF201609-4 交通規劃(100分)
阿新 • • 發佈:2019-01-03
試題編號: | 201609-4 |
試題名稱: | 交通規劃 |
時間限制: | 1.0s |
記憶體限制: | 256.0MB |
問題描述: |
問題描述
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。輸入保證每個城市都可以通過鐵路達到首都。 |
問題描述:參見上文。
問題分析:這是一個最優化的問題,也是一個單源最短路徑問題,所有要用Dijkstra演算法。題目要求在“所有城市乘坐高速鐵路到首都的最短路程和原來一樣長”的前提下,計算出“最少要改造多少鐵路”?
程式說明:圖的表示主要有三種形式,一是鄰接表,二是鄰接矩陣,三是邊列表。鄰接矩陣對於結點多和邊少的情況都不理想。程式中用鄰接表儲存圖,即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。程式中,這個邏輯體現在75行。
提交後得100分的C++語言程式如下:
/* CCF201609-4 交通規劃 */ #include <iostream> #include <vector> #include <queue> using namespace std; //#define DEBUG const int INT_MAX2 = ((unsigned int)(-1) >> 1); const int MAXN = 10000; // 邊 struct _edge { int v, cost; _edge(int v2, int c){v=v2; cost=c;} }; // 結點 struct _node { int u, cost; _node(){} _node(int u2, int c){u=u2; cost=c;} bool operator<(const _node n) const { return cost > n.cost; } }; vector<_edge> g[MAXN+1]; priority_queue<_node> q; int dist[MAXN+1]; int cost[MAXN+1]; bool visited[MAXN+1]; void dijkstra_add(int start, int n) { for(int i=0; i<=n; i++) { dist[i] = INT_MAX2; cost[i] = INT_MAX2; visited[i] = false; } dist[start] = 0; cost[start] = 0; q.push(_node(start, 0)); _node f; while(!q.empty()) { f = q.top(); q.pop(); int u = f.u; if(!visited[u]) { visited[u] = true; int len = g[u].size(); for(int i=0; i<len; i++) { int v2 = g[u][i].v; if(visited[v2]) continue; int tempcost = g[u][i].cost; int nextdist = dist[u] + tempcost; if(dist[v2] > nextdist) { dist[v2] = nextdist; cost[v2] = tempcost; // add code q.push(_node(v2, dist[v2])); } else if(dist[v2] == nextdist) cost[v2] = min(cost[v2], tempcost); // add code } } } } int main() { int n, m, src, dest, cost2; // 輸入資料,構建圖 cin >> n >> m; for(int i=1; i<=m; i++) { cin >> src >> dest >> cost2; g[src].push_back(_edge(dest, cost2)); g[dest].push_back(_edge(src, cost2)); } // 改進的Dijkstra演算法 dijkstra_add(1, n); #ifdef DEBUG cout << "dist : "; for(int i=1; i<=n; i++) cout << dist[i] << " "; cout << endl; cout << "cost : "; for(int i=1; i<=n; i++) cout << cost[i] << " "; cout << endl; #endif // 統計邊的權重 int ans=0; for(int i=2; i<=n; i++) ans += cost[i]; cout << ans << endl; return 0; }