POJ 2728 二分+最小生成树

题意:给n个点,可以将每个点的x,y的欧几里得距离(就是坐标系里两点距离公式)看作距离,z的差值即为费用差,求的是所有最小生成树中的min(边费用和/边距离和)。

思路:其实挑战P143有类似的列题,用的是二分枚举答案的方法,只不过不是树。这一题仅仅需要将题给图找出最小生成树,然后同样枚举即可。

虽然网上有许多高级的名词什么最优比率xxx之类的。。以及迭代的方法,不过我认为用二分也很好,易于想到也可以加深理解。

  1 #include <iostream>
  2 
  3 #include <string>
  4 
  5 #include <cstdio>
  6 
  7 #include <cstring>
  8 
  9 #include <cstdlib>
 10 
 11 #include <algorithm>
 12 
 13 #include <cmath>
 14 
 15 #define MAXN 1005
 16 
 17 #define INF 1000000000
 18 
 19 #define eps 1e-7
 20 
 21 using namespace std;
 22 
 23 int n;
 24 
 25 double Edge[MAXN][MAXN], lowcost[MAXN];
 26 
 27 int nearvex[MAXN];
 28 
 29 struct Point
 30 
 31 {
 32 
 33     int x, y, z;
 34 
 35 }p[MAXN];
 36 
 37 double cal(int a, int b)
 38 
 39 {
 40 
 41     return sqrt(1.0 * (p[a].x - p[b].x) * (p[a].x - p[b].x) + 1.0 * (p[a].y - p[b].y) * (p[a].y - p[b].y));
 42 
 43 }
 44 
 45 double prim(int src, double l)
 46 
 47 {
 48 
 49     double cost = 0, len = 0;
 50 
 51     double sum = 0;
 52 
 53     for(int i = 1; i <= n; i++)
 54 
 55     {
 56 
 57         nearvex[i] = src;
 58 
 59         lowcost[i] = abs(p[src].z - p[i].z) - Edge[src][i] * l;
 60 
 61     }
 62 
 63     nearvex[src] = -1;
 64 
 65     for(int i = 1; i < n; i++)
 66 
 67     {
 68 
 69         double mi = INF;
 70 
 71         int v = -1;
 72 
 73         for(int j = 1; j <= n; j++)
 74 
 75             if(nearvex[j] != -1 && lowcost[j] < mi)
 76 
 77             {
 78 
 79                 v = j;
 80 
 81                 mi = lowcost[j];
 82 
 83             }
 84 
 85         if(v != -1)
 86 
 87         {
 88 
 89             cost += abs(p[nearvex[v]].z - p[v].z);
 90 
 91             len += Edge[nearvex[v]][v];
 92 
 93             nearvex[v] = -1;
 94 
 95             sum += lowcost[v];
 96 
 97             for(int j = 1; j <= n; j++)
 98 
 99             {
100 
101                 double tmp = abs(p[v].z - p[j].z) - Edge[v][j] * l;
102 
103                 if(nearvex[j] != -1 && tmp < lowcost[j])
104 
105                 {
106 
107                     lowcost[j] = tmp;
108 
109                     nearvex[j] = v;
110 
111                 }
112 
113             }
114 
115         }
116 
117     }
118 
119     return sum;
120 
121 }
122 
123 int main()
124 
125 {
126 
127     while(scanf("%d", &n) != EOF && n)
128 
129     {
130 
131         for(int i = 1; i <= n; i++)
132 
133             scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
134 
135         for(int i = 1; i <= n; i++)
136 
137             for(int j = 1; j <= n; j++)
138 
139                 Edge[i][j] = cal(i, j);
140 
141         double low = 0, high = 10.0;             //其实二分20多次已经很足够了
142 
143         double l = 0.0, r = 100.0, mid;
144 
145         while(r - l > eps)
146 
147         {
148 
149             mid = (l + r) / 2;
150 
151             if(prim(1, mid) >= 0) l = mid;
152 
153             else r = mid;
154 
155         }
156 
157         printf("%.3f\n", r);
158 
159     }
160 
161     return 0;
162 
163 }
View Code

 

转载于:https://www.cnblogs.com/llllrj/p/9402294.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值