Desert King(POJ2728+最优比率生成树+二分)

题目链接:http://poj.org/problem?id=2728

题目:

题意:求一颗生成树,使得费用与距离的比值最小,其中距离等于两点之间的平面欧拉距离,费用为z坐标之差。

思路:

  由上图我们可以得知,我们只需对x进行二分(最大化平均值),以cost[i]-len[i]*x为边权跑prime即可。

代码实现如下:

 1 #include <set>
 2 #include <map>
 3 #include <queue>
 4 #include <stack>
 5 #include <cmath>
 6 #include <bitset>
 7 #include <cstdio>
 8 #include <string>
 9 #include <vector>
10 #include <cstdlib>
11 #include <cstring>
12 #include <iostream>
13 #include <algorithm>
14 using namespace std;
15 
16 typedef long long ll;
17 typedef pair<ll, ll> pll;
18 typedef pair<ll, int> pli;
19 typedef pair<int, ll> pil;;
20 typedef pair<int, int> pii;
21 typedef unsigned long long ull;
22 
23 #define lson i<<1
24 #define rson i<<1|1
25 #define bug printf("*********\n");
26 #define FIN freopen("D://code//in.txt", "r", stdin);
27 #define debug(x) cout<<"["<<x<<"]" <<endl;
28 #define IO ios::sync_with_stdio(false),cin.tie(0);
29 
30 const double eps = 1e-8;
31 const int mod = 10007;
32 const int maxn = 1000 + 7;
33 const double pi = acos(-1);
34 const int inf = 0x3f3f3f3f;
35 const ll INF = 0x3f3f3f3f3f3f3f;
36 
37 int n, x, y, z;
38 double ans;
39 int vis[maxn];
40 double mp[maxn][maxn], dis[maxn];
41 
42 struct node {
43     int x, y ,z;
44 }p[maxn];
45 
46 double dist(node& a, node& b) {
47     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
48 }
49 
50 bool prime(double x) {
51     for(int i = 1; i <= n; i++) {
52         dis[i] = inf;
53         vis[i] = 0;
54     }
55     ans = 0;
56     dis[1] = 0;
57     for(int i = 1; ; i++) {
58         double mx = inf;
59         int t = -1;
60         for(int j = 1; j <= n; j++) {
61             if(!vis[j] & mx > dis[j]) {
62                 mx = dis[j];
63                 t = j;
64             }
65         }
66         if(t == -1) break;
67         ans += mx;
68         vis[t] = 1;
69         for(int j = 1; j <= n; j++) {
70             if(!vis[j] && dis[j] > fabs(p[t].z - p[j].z) - mp[t][j] * x) {
71                 dis[j] = fabs(p[t].z - p[j].z) - mp[t][j] * x;
72             }
73         }
74     }
75     return ans >= 0;
76 }
77 
78 int main() {
79     //FIN;
80     while(~scanf("%d", &n) && n) {
81         for(int i = 1; i <= n; i++) {
82             scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
83         }
84         for(int i = 1; i <= n; i++) {
85             for(int j = 1; j <= n; j++) {
86                 mp[i][j] = dist(p[i], p[j]);
87             }
88         }
89         double ub = 100, lb = 0, mid;
90         while(ub - lb > eps) {
91             mid = (ub + lb) / 2;
92             if(prime(mid)) lb = mid;
93             else ub = mid;
94         }
95         printf("%.3f\n", lb);
96     }
97     return 0;
98 }

 

转载于:https://www.cnblogs.com/Dillonh/p/9414765.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值