题意:

给定n个村子的坐标(x,y)和高度z, 求出修n-1条路连通所有村子, 并且让 修路花费/修路长度 最少的值

两个村子修一条路, 修路花费 = abs(高度差), 修路长度 = 欧氏距离

分析:

01分数划分的题目, 构造出 d[i] = 修路花费 - L * 修路长度, 这个L值我们可以二分(这道题看数据范围的话二分上限其实挺大的, 但其实上限取到100就可以过), 也可以用Dinkelbach迭代出来。

二分(1422ms)

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <iostream>
  4. #include <iostream>
  5. #include <algorithm>
  6. #include <vector>
  7. #include <queue>
  8. #include <set>
  9. #include <map>
  10. #include <cstring>
  11. #include <cmath>
  12. #define rep(i,a,b) for(int i = a; i < b;i++)
  13. #define _rep(i,a,b) for(int i = a; i <= b;i++)
  14. using namespace std;
  15. const int maxn = + ;
  16. const double inf = 1e9 + ;
  17. const double eps = 1e-;
  18. int n;
  19.  
  20. double G[maxn][maxn];
  21. double x[maxn], y[maxn], z[maxn];
  22.  
  23. inline double p2p_dis(double x1, double y1, double x2, double y2){
  24. return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  25. }
  26. double prim(double L){
  27. double tree_dis = ;
  28. double dis[maxn];
  29. int vis[maxn];
  30. fill(dis, dis + maxn, inf);
  31. memset(vis, ,sizeof(vis));
  32.  
  33. dis[] = ;
  34. vis[] = ;
  35.  
  36. for(int i = ; i < n; i++) dis[i] = abs(z[] - z[i]) - L * G[][i];
  37.  
  38. for(int times = ; times < n - ; times++){
  39. int picked = -;
  40. double min_dis = inf;
  41. for(int i = ; i < n; i++){
  42. if(!vis[i] && dis[i] < min_dis){
  43. min_dis = dis[i];
  44. picked = i;
  45. }
  46. }
  47. tree_dis += min_dis;
  48. vis[picked] = ;
  49. for(int i = ; i < n; i++)
  50. if(!vis[i])
  51. dis[i] = min(dis[i] , abs(z[picked] - z[i]) - L * G[picked][i]) ;
  52. }
  53. return tree_dis;
  54. }
  55.  
  56. int main(){
  57. // freopen("1.txt","r", stdin);
  58. while(cin >> n && n){
  59. rep(i,,n) cin >> x[i] >> y[i] >> z[i];
  60. rep(i,,n) rep(j,i+,n) G[i][j] = G[j][i] = p2p_dis(x[i],y[i],x[j],y[j]);
  61. double l = , r = ;
  62. while(abs(r - l) > eps){
  63. double mid = (l + r) / ;
  64. // printf("%.3f\n", mid);
  65. if(prim(mid) >= ){
  66. l = mid;
  67. }else{
  68. r = mid;
  69. }
  70. }
  71. printf("%.3f\n", l);
  72. }
  73. return ;
  74. }

Dinkelbach(204ms)

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <iostream>
  4. #include <iostream>
  5. #include <algorithm>
  6. #include <vector>
  7. #include <queue>
  8. #include <set>
  9. #include <map>
  10. #include <cstring>
  11. #include <cmath>
  12. #define rep(i,a,b) for(int i = a; i < b;i++)
  13. #define _rep(i,a,b) for(int i = a; i <= b;i++)
  14. using namespace std;
  15. const int maxn = + ;
  16. const double inf = 1e9 + ;
  17. const double eps = 1e-;
  18. int n;
  19.  
  20. double G[maxn][maxn];
  21. double x[maxn], y[maxn], z[maxn];
  22.  
  23. inline double p2p_dis(double x1, double y1, double x2, double y2){
  24. return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  25. }
  26. double prim(double L){
  27. double ele = , deno = ; //分子分母
  28. double dis[maxn];
  29. int near[maxn]; //开一个数组记录每次选中是哪一条边
  30.  
  31. int vis[maxn];
  32. fill(dis, dis + maxn, inf);
  33. memset(vis, ,sizeof(vis));
  34. memset(near, -, sizeof(near));
  35. dis[] = ;
  36. vis[] = ;
  37.  
  38. for(int i = ; i < n; i++) dis[i] = abs(z[] - z[i]) - L * G[][i], near[i] = ; //每个点都是由0点更新的, 所以near都是0
  39.  
  40. for(int times = ; times < n - ; times++){
  41. int picked = -;
  42. double min_dis = inf;
  43. for(int i = ; i < n; i++){
  44. if(!vis[i] && dis[i] < min_dis){
  45. min_dis = dis[i];
  46. picked = i;
  47. }
  48. }
  49. ele += abs(z[near[picked]] - z[picked]);//分子是选的路程
  50. deno += G[near[picked]][picked]; //分母是真实的花费
  51. vis[picked] = ;
  52. for(int i = ; i < n; i++)
  53. if(!vis[i] && dis[i] > abs(z[picked] - z[i]) - L * G[picked][i]){
  54. dis[i] = abs(z[picked] - z[i]) - L * G[picked][i];
  55. near[i] = picked;//如果通过picked点更新dis,那么该位置near就是picked
  56. }
  57.  
  58. }
  59.  
  60. return ele/deno; //注意返回的跟二分不一样, 应该返回当前L下真正题目的所求
  61. }
  62.  
  63. int main(){
  64. // freopen("1.txt","r", stdin);
  65. while(cin >> n && n){
  66. rep(i,,n) cin >> x[i] >> y[i] >> z[i];
  67. rep(i,,n) rep(j,i+,n) G[i][j] = G[j][i] = p2p_dis(x[i],y[i],x[j],y[j]);
  68. double L, ans = ;
  69. while(){
  70. L = ans;
  71. ans = prim(L); //这是一个真实值, 不是含L的变式
  72. if(abs(ans - L)< eps) break;
  73. }
  74. printf("%.3f\n", ans);
  75. }
  76. return ;
  77. }

POJ 2728 Desert King(最优比率生成树, 01分数规划)的更多相关文章

  1. POJ 2728 Desert King 最优比率生成树

    Desert King Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20978   Accepted: 5898 [Des ...

  2. POJ.2728.Desert King(最优比率生成树 Prim 01分数规划 二分/Dinkelbach迭代)

    题目链接 \(Description\) 将n个村庄连成一棵树,村之间的距离为两村的欧几里得距离,村之间的花费为海拔z的差,求花费和与长度和的最小比值 \(Solution\) 二分,假设mid为可行 ...

  3. POJ 2728 Desert King(最优比率生成树 01分数规划)

    http://poj.org/problem?id=2728 题意: 在这么一个图中求一棵生成树,这棵树的单位长度的花费最小是多少? 思路: 最优比率生成树,也就是01分数规划,二分答案即可,题目很简 ...

  4. Desert King (poj 2728 最优比率生成树 0-1分数规划)

    Language: Default Desert King Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 22113   A ...

  5. POJ 2728 Desert King (最优比率树)

    题意:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可,建造水管距离为坐标之间的欧几里德距离,费用为海拔之差,现在要求方案使得费用与距离的比值最小,很显然,这个题目 ...

  6. POJ 2728 Desert King (最优比例生成树)

    POJ2728 无向图中对每条边i 有两个权值wi 和vi 求一个生成树使得 (w1+w2+...wn-1)/(v1+v2+...+vn-1)最小. 采用二分答案mid的思想. 将边的权值改为 wi- ...

  7. Desert King(最优比率生成树)

    Desert King Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 22717   Accepted: 6374 Desc ...

  8. POJ2728 Desert King —— 最优比率生成树 二分法

    题目链接:http://poj.org/problem?id=2728 Desert King Time Limit: 3000MS   Memory Limit: 65536K Total Subm ...

  9. 【POJ2728】Desert King 最优比率生成树

    题目大意:给定一个 N 个点的无向完全图,边有两个不同性质的边权,求该无向图的一棵最优比例生成树,使得性质为 A 的边权和比性质为 B 的边权和最小. 题解:要求的答案可以看成是 0-1 分数规划问题 ...

随机推荐

  1. FZu Problem 2236 第十四个目标 (线段树 + dp)

    题目链接: FZu  Problem 2236 第十四个目标 题目描述: 给出一个n个数的序列,问这个序列内严格递增序列有多少个?不要求连续 解题思路: 又遇到了用线段树来优化dp的题目,线段树节点里 ...

  2. 题解报告:poj 1985 Cow Marathon(求树的直径)

    Description After hearing about the epidemic of obesity in the USA, Farmer John wants his cows to ge ...

  3. Java图解

    java虚拟机 JVM运行过程: java开发工具包 java入门图解1 java入门图解2 java入门图解3 java入门图解4

  4. H5页面快速搭建之高级字体应用实践

    原文出处: 淘宝前端团队(FED)- 龙驭 背景 最近在开发一个 H5 活动页快速搭建平台,可以通过拖拽编辑图片,文字等元素组件,快速搭建出一个移动端的活动页面,基本交互和成品效果类似 PPT 软件. ...

  5. AJPFX:求两个城市之间的距离

    键盘录入多个城市: 城市1,城市2,城市3  以 ### 结束输出然后再键盘录入各个城市之间的距离:  格式如下:0,12,4512,0,2245,22,0### 然后按照输入的两个城市,求得两个城市 ...

  6. poj2184 Cow Exhibition

    思路: dp+滚动数组. 类似01背包. 实现: #include <iostream> #include <cstdio> #include <algorithm> ...

  7. JS进阶-特殊形式的函数-内部私有函数

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Android虚拟机电池状态设置

    问题描述: 安装SDK后使用AVD配合APPIUM进行测试,此时虚拟机的电池状态为0%充电中:部分APP会对手机电池状态有要求,不符合要求时,无法安装或打开. 解决思路: 1.Android系统设置( ...

  9. win应用只允许单个实例运行,并将已运行实例窗口置顶

    关键词:windows,c++,桌面应用,单个实例,窗口置顶 目标:1.判断本程序是否已有一个实例在运行.2.若有,则激活已在运行的实例(将其窗口置顶),并退出当前运行. 1.使用semaphore来 ...

  10. Javaweb学习笔记7—JDBC技术

      今天来讲javaweb的第7阶段学习. JDBC技术,关于JDBC本篇博客只介绍了它的一部分,后面博客会更加深入探讨. 老规矩,首先先用一张思维导图来展现今天的博客内容.   ps:我的思维是用的 ...