• POJ2728 最小比率生成树/0-1分数规划/二分/迭代(迭代不会)


    用01分数规划 + prime + 二分 竟然2950MS惊险的过了QAQ

    前提是在TLE了好几次下过的 = =

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

    解题思路:

    对答案进行二分,当把代进去的答案拿来算最小生成树的时候,一旦总路径长度为0,就是需要的答案。


    0-1规划是啥?
     
    概念
    有带权图G, 对于图中每条边e[i], 都有benifit[i](收入)和cost[i](花费), 我们要求的是一棵生成树T, 它使得 ∑(benifit[i]) / ∑(cost[i]), i∈T 最大(或最小).这显然是一个具有现实意义的问题.
    解法之一 0-1分数规划
    设x[i]等于1或0, 表示边e[i]是否属于生成树.
    则我们所求的比率 r = ∑(benifit[i] * x[i]) / ∑(cost[i] * x[i]), 0≤i<m .
    为了使 r 最大, 设计一个子问题---> 让 z = ∑(benifit[i] * x[i]) - l * ∑(cost[i] * x[i]) = ∑(d[i] * x[i]) 最大 (d[i] = benifit[i] - l * cost[i]) , 并记为z(l). 我们可以兴高采烈地把z(l)看做以d为边权的最大生成树的总权值.

    然后明确两个性质:
     1. z单调递减
      证明: 因为cost为正数, 所以z随l的减小而增大.
     2. z( max(r) ) = 0
      证明: 若z( max(r) ) < 0, ∑(benifit[i] * x[i]) - max(r) * ∑(cost[i] * x[i]) < 0, 可化为 max(r) < max(r). 矛盾;
       若z( max(r) ) >= 0, 根据性质1, 当z = 0 时r最大.

    贴代码:

     1 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler
     2 #include <stdio.h>
     3 #include <iostream>
     4 #include <climits>
     5 #include <cstring>
     6 #include <cmath>
     7 #include <stack>
     8 #include <vector>
     9 #include <algorithm>
    10 #define ll long long
    11 using namespace std;
    12 
    13 const int INF = 0x3f3f3f3f;
    14 const int MAXN = 1001;
    15 struct node{
    16     double x,y,h;
    17 }dot[MAXN];
    18 
    19 double map[MAXN][MAXN];
    20 int n;
    21 double dis(double x1,double y1,double x2,double y2){
    22     return sqrt( (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1) );
    23 }
    24 
    25 void creat(int n,double l){
    26     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
    27         map[i][j]=fabs(dot[i].h-dot[j].h) - l * dis(dot[i].x,dot[i].y,dot[j].x,dot[j].y);
    28 }
    29 
    30 double prim(){
    31     bool vis[MAXN];
    32     memset(vis, 0, sizeof(vis));
    33     double dis[MAXN];
    34     double ans = 0;
    35     int i,j;
    36     vis[1] = true;
    37     for(i = 1; i <= n; ++i)
    38         dis[i] = map[1][i];
    39     for(i = 1; i < n; ++i){
    40         int temp = INF, flag;
    41         for(j = 1; j <= n; ++j){
    42             if(!vis[j] && dis[j] <= temp){
    43                 temp = dis[j];
    44                 flag = j;
    45             }
    46         }
    47         vis[flag] = true;
    48         ans += dis[flag];
    49         for(j = 1; j <= n; ++j){
    50             if(!vis[j] && map[flag][j] < dis[j])
    51                 dis[j] = map[flag][j];
    52         }
    53     }
    54     return ans;
    55 }
    56 
    57 int main(){
    58     int i,j;
    59     double res,front,rear, mid;
    60     while(EOF != scanf("%d",&n)){
    61         if(n==0)    break;
    62         for(i=1;i<=n;i++)
    63             scanf("%lf%lf%lf",&dot[i].x,&dot[i].y,&dot[i].h);
    64         front = 0;
    65         rear = 100.0;//doubt
    66         while(front <= rear){
    67             mid = (front + rear) / 2;
    68             creat(n,mid);
    69             res = prim();
    70             if(fabs(res) < 1e-4)
    71                 break;
    72             else if(res > 1e-4)
    73                 front = mid;
    74             else
    75                 rear = mid;
    76         }
    77         printf("%.3f
    ",mid);
    78     }
    79     return 0;
    80 }
  • 相关阅读:
    SpringMvc与Struts2的对比
    Spring 通知
    Spring 之 AOP
    Spring 之 IOC
    Spring IOC 和 AOP概述
    JSON与JAVA数据的相互转换
    (4)-optXXX方法的使用
    (3)-JSONObject的过滤设置
    (2)-生成JSONObject的方法
    String 类型的相关转换
  • 原文地址:https://www.cnblogs.com/wushuaiyi/p/3898977.html
Copyright © 2020-2023  润新知