【CCF 201609-4】交通規劃(最小的最短路徑樹 Dijkstra)
阿新 • • 發佈:2018-12-10
題目抽象
要求所有結點與源結點連通,使得所有邊權之和最小。即求最小的最短路徑樹。
大致思路
演算法:通過Dijkstra演算法可以構建最短路徑樹,如何保證這棵樹最小呢?這就需要一些變形了:
每個結點需要記錄它的前驅邊,每次鬆弛的條件是u.d + e ≤ v.d,若e比當前的前驅邊短,則需要更新前驅邊為e
實現:由於n達到了10^4,因此需要採用佇列優化(鄰接表儲存Edge的編號)
#include <iostream> #include <cstring> #include <queue> #include <vector> using namespace std; struct Edge { int beg,end,len; Edge(int a, int b, int c):beg(a),end(b),len(c) {} }; vector<Edge> edges; int pi[10005]; struct Node { int num, d; friend bool operator < (const Node& a, const Node& b) { if(a.d != b.d) return a.d > b.d; return edges[pi[a.num]].len > edges[pi[b.num]].len; } Node(int a, int b):num(a),d(b) {} }; const int inf = 1e8; int n,m,a,b,c,cur; vector<int> adj[10005]; priority_queue<Node> que; bool vis[10005]; int d[10005]; void init() { que.push(Node(1,0)); for(int i=1; i<=n; ++i) { d[i] = inf; pi[i] = -1; } d[1] = 0; } void addEdge(int a, int b, int c) { edges.push_back(Edge(a,b,c)); adj[a].push_back(edges.size()-1); } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>m; for(int i=0; i<m; ++i) { cin>>a>>b>>c; addEdge(a,b,c); addEdge(b,a,c); } init(); while(!que.empty()) { cur = que.top().num; que.pop(); if(vis[cur]) continue; for(int i=0; i<adj[cur].size(); ++i) { Edge& e = edges[adj[cur][i]]; //核心點 if(vis[e.end]==0 && (d[e.end] > d[cur] + e.len || (d[e.end] == d[cur] + e.len && edges[pi[e.end]].len > e.len) )) { d[e.end] = d[cur] + e.len; pi[e.end] = adj[cur][i]; que.push(Node(e.end, d[e.end])); } } } int sum = 0; for(int i=1; i<=n; ++i) if(pi[i] != -1) sum += edges[pi[i]].len; cout<<sum; return 0; }