计蒜客:圣诞树(dijkstra,特殊的生成树)

 

基础原理:特殊的生成树

给定一张无向图,其中边权都是正数,你需要求出总代价最小的生成树,生成树上每条边 (u,v)(u,v) 的代价为 w(u,v)∗count(v)w(u,v)count(v),其中 w(u,v)w(u,v) 为边 (u,v)(u,v) 的权值,count(v)count(v) 是 vv 所在子树的结点数总和。

解法:虽然看起来是一道生成树的题,实际上却是一道单源最短路的题目。我们把整棵树的代价加起来,实际上就等于从根结点出发到每个顶点的最短路之和。因此,从每个顶点出发求一遍单源最短路,取其中最短路总和最小的一个顶点作为根,其到所有顶点的单源最短路的总和就是最终答案。

但这题还给结点加上了权值,我们在计算结点的贡献值时需要乘上结点的权值(其实我没搞懂为啥直接乘就行了,不过推几个样例就能得到这个结果)。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n, m;
 4 long long maximum = 0x3f3f3f3f;
 5 long long res = 0;  
 6 typedef pair<int, int> pii;
 7 
 8 vector<pii> graph[50005];
 9 vector<int> weight(50005, 0);
10 int dis[50005];
11 set<pii, less<pii> > minHeap;
12 bool visited[50005];
13 
14 bool dijkstra(int p) {
15     memset(visited, false, sizeof(visited));
16     memset(dis, 0x3f, sizeof(dis));
17     minHeap.clear();
18     minHeap.insert(make_pair(0, p));
19     dis[p] = 0;
20     visited[p] = true;
21     
22     while(!minHeap.empty()) {
23         auto node = minHeap.begin();
24         int root = node -> second;
25         minHeap.erase(node);
26         visited[root] = true;
27         if (dis[root] >= maximum) { //存在无法到达的结点
28             return false;
29         }
30         res += dis[root] * weight[root]; //计算总价值
31         
32         for (auto iter : graph[root]) {
33             if (!visited[iter.first]) {
34                 int child = iter.first;
35                 int value = iter.second;
36                 if (value + dis[root] < dis[child]) {
37                     minHeap.erase(make_pair(dis[child], child));
38                     dis[child] = dis[root] + value;
39                     minHeap.insert(make_pair(dis[child], child));
40                 }
41             }
42         }
43     }
44     return true;             
45 }
46 int main() {
47     cin >> n >> m;
48     for (int i = 1; i <= n; ++ i) {
49         scanf("%d", &weight[i]);
50     }
51     int a, b, c;
52     for (int i = 0; i < m; ++ i) {
53         cin >> a >> b >> c;
54         graph[a].push_back(make_pair(b, c));
55         graph[b].push_back(make_pair(a, c));
56     }
57     if (dijkstra(1)) { //树根固定为1
58         cout << res;
59     } else {
60         cout << "No Answer";
61     }
62     
63 }

 

posted on 2024-11-12 23:45  Coder何  阅读(45)  评论(0)    收藏  举报