当前位置:   article > 正文

最小生成树非模板题 入门已过进阶未满 (AcWing 346 poj 2728 )_最小生成树(非模板)

最小生成树(非模板)

1.AcWing 346 走廊泼水节

题目:https://www.acwing.com/problem/content/description/348/

用kruskal算法的思想,每加入一条边的时候,假如这条边的左右端点的祖先不属于同一个集合(并查集),就说明这两个集合是分开来的

如图,s1,s2集合,假设此时的边连接的是1,4两点,长度为z

因为最后需要生成完全图,意味着点和点之间必定有边,那么我们此时考虑s1和s2集合的点

除开1,4之外,假如有任意两个点之间的距离小于z的话,此时1,4这条边就不会作为最小生成树的其中一条边之一。

为了使得最后完全图的边长最小,而此时除了1,4两点之间的距离可以为z,其他都要大于z,因此取z+1

对于两个集合,两两点之间搭建一条z+1的边,总共为 (3*3-1)*(z+1)的长度

合并后因为这些点两两已经有边,因此将他们看成一个整体,以后合并的时候就不需要考虑他们内部的情况了

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 1e4;
  4. struct edge {
  5. int fro, to, val;
  6. }e[maxn];
  7. bool cmp(edge a, edge b) {
  8. return a.val < b.val;
  9. }
  10. int f[maxn], siz[maxn]; //f:并查集 siz:该并查集的大小(元素个数)
  11. int n, ans;
  12. int find(int x) {
  13. return f[x] == x ? x : f[x] = find(f[x]);
  14. }
  15. void init() {
  16. ans = 0;
  17. for (int i = 1; i <= n; i++) f[i] = i, siz[i] = 1;
  18. }
  19. void kruskal() {
  20. sort(e + 1, e + n, cmp);
  21. int lef = n - 1;
  22. for (int i = 1; i < n; i++) {
  23. int fa = find(e[i].fro), fb = find(e[i].to);
  24. if (fa == fb) continue;
  25. ans += (siz[fa] * siz[fb] - 1)*(e[i].val + 1);
  26. f[fa] = fb;
  27. siz[fb] += siz[fa];
  28. if (--lef == 0) break;
  29. }
  30. cout << ans << endl;
  31. }
  32. int main() {
  33. int t;
  34. cin >> t;
  35. while (t--) {
  36. cin >> n;
  37. init();
  38. for (int i = 1; i < n; i++)
  39. scanf("%d %d %d", &e[i].fro, &e[i].to, &e[i].val);
  40. kruskal();
  41. }
  42. return 0;
  43. }

 

 

poj 2728 Desert King

原题:https://vjudge.net/problem/POJ-2728#author=CMinusMinus

(我直接看翻译了,英语太烂。。)

这道题是0/1分数规划 + 最优比率生成树

0/1 分数规划可以用二分答案来做

(注意下面的cost表示花费,val表示价值,均被我省略了数组下标)

题目要求这个东西最小

也就是存在一个最小的k,使得:

转化为乘法:

合并求和符号

也就是说,存在一个最小的k,使得上面这条式子成立

二分k,构建一棵最小生成树,点和点的权值为 cost[i]-k*val[i],假如式子大于等于0,则r=mid,否则l=mid

而这是完全图,对于每一次二分:

建边要n^2时间复杂度

假如使用kruskal,边的数量有m= n^2(完全图),kruskal时间复杂度=mlogm = 2n^2logn,

使用kruskal总的时间复杂度n^4logn  超时

此题应该使用普里姆算法(完全图,边多)

因为是完全图,所以普里姆的堆优化没用(应该是这样的),使用堆优化的prim反而超时,要使用普通的普里姆

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<queue>
  5. #include<cstring>
  6. #include<map>
  7. #include<cmath>
  8. #define ll long long
  9. using namespace std;
  10. //const int INF = 0x3f3f3f3f;
  11. const double INF = 1e10;
  12. const int maxn = 1e3 + 7;
  13. int xx[maxn], yy[maxn], h[maxn];
  14. double m[maxn][maxn], cost[maxn][maxn];
  15. double vv[maxn][maxn];
  16. int n;
  17. void makevv(double k) {
  18. for (int i = 1; i <= n; i++) {
  19. for (int j = i + 1; j <= n; j++) {
  20. vv[i][j] = cost[i][j] - k * m[i][j];
  21. vv[j][i] = vv[i][j];
  22. }
  23. }
  24. }
  25. double dis[maxn];
  26. bool vis[maxn];
  27. int prim() {
  28. double ans = 0;
  29. memset(vis, 0, sizeof(vis));
  30. for (int i = 1; i <= n; i++) dis[i] = INF;
  31. dis[1] = 0;
  32. vis[1] = 1;
  33. int now = 1;
  34. for (int i = 1; i < n; i++) { //i<=n
  35. double minn = INF;
  36. int k = 1;
  37. for (int j = 1; j <= n; j++) {
  38. if (!vis[j]) {
  39. if (dis[j] > vv[now][j]) dis[j] = vv[now][j];
  40. if (dis[j] < minn) minn = dis[j], k = j;
  41. }
  42. }
  43. vis[k] = 1;
  44. ans += minn;
  45. cout << k << " ans= " << ans << endl;
  46. now = k;
  47. }
  48. return ans > 0;
  49. }
  50. int main() {
  51. while (cin >> n, n) {
  52. for (int i = 1; i <= n; i++) scanf("%d %d %d", xx + i, yy + i, h + i);
  53. double fl = 0;
  54. for (int i = 1; i <= n; i++) {
  55. for (int j = i + 1; j <= n; j++) {
  56. m[i][j] = sqrt((double)(xx[i] - xx[j])*(xx[i] - xx[j]) + (double)(yy[i] - yy[j])*(yy[i] - yy[j]));
  57. cost[i][j] = (double)abs(h[i] - h[j]);
  58. fl = max(fl, cost[i][j] / m[i][j]);
  59. }
  60. }
  61. double l = 0, r = fl, mid = 0;
  62. while (r - l > 1e-6) {
  63. mid = (l + r) / 2;
  64. makevv(mid);
  65. int flag = prim();
  66. if (flag == 1) l = mid;
  67. else r = mid;
  68. }
  69. //printf("%.3lf\n", mid); //用c++交用这个
  70. printf("%.3f\n", mid);//用g++交用这个
  71. }
  72. return 0;
  73. }

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/52807
推荐阅读
相关标签
  

闽ICP备14008679号