题目链接:
http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3946
题解:
用dijkstra跑单元最短路径,如果对于顶点v,存在一系列边(ui,v)使得dis[v]最小(dis[v]表示0到v的距离)。这些边能且只能选一条,那么我们自然应该选cost最小的那个边了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<vector> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 9 typedef long long LL; 10 const int maxn = 1e5 + 10; 11 12 struct Edge { 13 int ne, u, v, c, d; 14 Edge(int ne, int u, int v, int d, int c) :ne(ne), u(u), v(v), d(d), c(c) {} 15 Edge() {} 16 }egs[maxn * 2]; 17 18 struct Heap { 19 int u, d, c; 20 Heap(int u, int d) :u(u), d(d) {} 21 Heap() {} 22 bool operator < (const Heap& tmp) const { 23 return d>tmp.d; 24 } 25 }; 26 27 struct Node { 28 int u, v, w; 29 bool operator < (const Node& tmp) const { 30 return w<tmp.w; 31 } 32 }nds[maxn]; 33 34 35 int head[maxn], tot; 36 37 void addEdge(int u, int v, int d, int c) { 38 egs[tot] = Edge(head[u], u, v, d, c); 39 head[u] = tot++; 40 } 41 42 int n, m; 43 LL ans_d, ans_c; 44 45 LL dis[maxn]; 46 //pre[u]记录u和前驱节点的那条边的cost 47 int pre[maxn]; 48 bool done[maxn]; 49 50 51 void dij() { 52 for (int i = 0; i<n; i++) { 53 dis[i] = 2e10; 54 } 55 memset(done, false, sizeof(done)); 56 priority_queue<Heap> pq; 57 dis[0] = 0; 58 pq.push(Heap(0, 0)); 59 while (!pq.empty()) { 60 Heap x = pq.top(); pq.pop(); 61 int u = x.u; 62 if (done[u]) continue; 63 done[u] = true; 64 int p = head[u]; 65 while (p != -1) { 66 Edge &e = egs[p]; 67 if (dis[e.v]>dis[u] + e.d) { 68 dis[e.v] = dis[u] + e.d; 69 pre[e.v] = e.c; 70 pq.push(Heap(e.v, dis[e.v])); 71 } 72 else if (dis[e.v] == dis[u] + e.d) { 73 //这里贪心选cost最小的边 74 if (pre[e.v]>e.c) 75 pre[e.v] = e.c; 76 } 77 p = e.ne; 78 } 79 } 80 ans_d = 0; ans_c = 0; 81 for (int i = 0; i<n; i++) { 82 ans_d += dis[i]; 83 } 84 for (int i = 1; i<n; i++) { 85 ans_c += pre[i]; 86 } 87 } 88 89 void init() { 90 memset(head, -1, sizeof(head)); 91 memset(pre, -1, sizeof(pre)); 92 tot = 0; 93 } 94 95 int main() { 96 // freopen("data_in.txt","r",stdin); 97 int tc; 98 scanf("%d", &tc); 99 while (tc--) { 100 scanf("%d%d", &n, &m); 101 init(); 102 for (int i = 0; i<m; i++) { 103 int u, v, d, c; 104 scanf("%d%d%d%d", &u, &v, &d, &c); 105 addEdge(u, v, d, c); 106 addEdge(v, u, d, c); 107 } 108 dij(); 109 printf("%lld %lld ", ans_d, ans_c); 110 } 111 return 0; 112 }