• 01分数规划


    问题:给定一个正整数m和两个正数数组a[n]和b[n]。对于数组x[n],x[n]中有m个i使得x[i] = 0,其余x[i] = 1,并且令R = segma(a[i]*x[i]) / segma(b[i]*x[i])。求一个满足条件的x[n],使得R的值最大,输出R的最大值。

    分析:构造函数F(L) = segma(a[i]*x[i]) - L * segma(b[i]*x[i]) = segma((a[i] - L * b[i]) * x[i])。令c[i] = a[i] - L * b[i]。

       观察F(L),发现以下性质:1、若L固定,则可以通过一次对c[i]的排序,找到使得F(L)取最值的数组x[n];2、若x[n]固定,则F(L)随L的增大而减小;3、在2的基础上发现,即使x[n]不固定,F(L)也随着L的增大而减小;4、对于L0,若有F(L0) > 0,则由代数变形可知segma(a[i]*x[i]) / segma(b[i]*x[i]) > L0,所以R > L0。同理,若F(L0) < 0,则R < L0,若F(L0) = 0,则R = L0。

       则由性质3,4可知,该问题能用二分法得到解决。

       -------------------------------------------------------------二分法-------------------------------------------------------

       设置下界l和上届r,mid = (l+r)/2。另c[i] = a[i] - mid*b[i],选出最大的(n-m)个c[i]之和,若和大于等于0,则l = mid,否则r = mid,直到满足精度为止。

       -----------------------------------------------------Dinkelbach算法分析------------------------------------------------

       但是,二分法解决此问题速度比较慢,还有一种难懂但是速度更快的算法Dinkelbach。

       对F(L),设F(R) = 0。首先,随机选择一个数k1有两种情况:1、若F(k1) > 0,则k1 < R,记使得F(k1)取最大值的数组x[n]为x1[n]。令k2 = segma(a[i]*x1[i]) / segma(b[i]*x1[i]),由题设易知,k2 <= R,而F(k1) > 0 = F(k2),故k2 > k1,所以有k1 < k2 <= R,故令k1 = k2可更接近R,且下一次仍然有F(k1) > 0;2、F(k1) < 0,则k1 > R,记使得F(k1)取得最大值的数组x[n]为x2[n]。令k2 = segma(a[i]*x2[i]) / segma(b[i]*x2[i]),由题设知k2 <= R,则令k1 = k2,从下依次开始,一直有F(k1) > 0,由第一种情况组成循环。故可以不断通过k1 = k2的方式使得k1 更接近R。

       -------------------------------------------------------Dinkelbach算法--------------------------------------------------

       随机取一个数k,令c[i] = a[i] - k * b[i]并对c[i]进行排序,选出最大的m个,令k' = segma(a'[]) / segma(b'[]),(其中a'[]和b'[]事排序后选出来的最大的m个),若k'与k的差距在精度局限内则输出,否则k = k',循环上诉步骤。

    参考资料:http://www.cnblogs.com/perseawe/archive/2012/05/03/01fsgh.html

         http://blog.sina.com.cn/s/blog_6383bcba0100xf4z.html

         http://hi.baidu.com/misshanli/item/ad81b23110f7ccb3134b14c3

    例题:

    1、POJ 2976 Dropping tests

    题意:给定一个正整数m和两个正数数组a[n]和b[n]。对于数组x[n],x[n]中有m个i使得x[i] = 1,其余x[i] = 0,并且令R = segma(a[i]*x[i]) / segma(b[i]*x[i])。求一个满足条件的x[n],使得R的值最大,输出R的最大值。(注意看,与上面的题目有所不同)

       1 <= n <= 1000,0 <= m < n,0 <= ai <= bi <= 10^9。

    解法:不多说,完全就是上面那样。直接看代码。

    tag:math, 01分数规划

    二分法:

     1 /*
     2  * Author:  Plumrain
     3  * Created Time:  2013-10-13 10:18
     4  * File Name: math-POJ-2976.cpp
     5  * 二分法
     6  */
     7 #include<iostream>
     8 #include<cstdio>
     9 #include<cstring>
    10 #include<cmath>
    11 #include<algorithm>
    12 
    13 using namespace std;
    14 
    15 #define CLR(x) memset(x, 0.0, sizeof(x))
    16 
    17 const double eps = 1e-4;
    18 const int N = 1000;
    19 
    20 int n, m;
    21 int a[N+5], b[N+5];
    22 double c[N+5];
    23 
    24 bool cmp(double x, double y)
    25 {
    26     return x > y;
    27 }
    28 
    29 double gao()
    30 {
    31     double l = 0.0, r = 1.0;
    32     while (l + eps < r){
    33         double mid = (l+r) / 2.0;
    34         CLR (c);
    35         for (int i = 0; i < n; ++ i)
    36             c[i] = a[i] - mid * b[i];
    37         sort(c, c+n, cmp);
    38         double tmp = 0.0;
    39         for (int i = 0; i < n-m; ++ i)
    40             tmp += c[i];
    41         if (tmp >= eps) l = mid;
    42         else r = mid;
    43     }
    44     return l;
    45 }
    46 
    47 int main()
    48 {
    49     while (scanf ("%d%d", &n, &m) != EOF && n){    
    50         for (int i = 0; i < n; ++ i)
    51             scanf ("%d", &a[i]);
    52         for (int i = 0; i < n; ++ i)
    53             scanf ("%d", &b[i]);
    54         
    55         printf ("%d
    ", (int)(gao()*100.0 + 0.5));
    56     }
    57     return 0;
    58 }
    View Code

    Dinkelbach算法:

     1 /*
     2  * Author:  Plumrain
     3  * Created Time:  2013-10-13 17:29
     4  * File Name: math-POJ-2976-2.cpp
     5  * Dinkelbach算法
     6  */
     7 #include<iostream>
     8 #include<cstdio>
     9 #include<cstring>
    10 #include<cmath>
    11 #include<algorithm>
    12 #include<vector>
    13 #include<utility>
    14 
    15 using namespace std;
    16 
    17 #define CLR(x) memset(x, 0.0, sizeof(x))
    18 #define PB push_back
    19 
    20 const double eps = 1e-4;
    21 const int N = 1000;
    22 
    23 int n, m;
    24 int a[N+5], b[N+5];
    25 vector<pair<double, int> > cur;
    26 
    27 bool cmp(pair<double, int> x, pair<double, int> y)
    28 {
    29     return x.first > y.first;
    30 }
    31 
    32 double gao()
    33 {
    34     double p = 0.5, q = 0.0;
    35     while (1){
    36         cur.clear();
    37         for (int i = 0; i < n; ++ i){
    38             double c = a[i] - p * b[i];
    39             cur.PB (make_pair(c, i));
    40         }
    41         sort (cur.begin(), cur.end(), cmp);
    42         double tmp1 = 0.0, tmp2 = 0.0;
    43         for (int i = 0; i < n-m; ++ i){
    44             tmp1 += a[cur[i].second];
    45             tmp2 += b[cur[i].second];
    46         }
    47         q = tmp1 / tmp2;
    48         if (fabs(p-q) < eps) break;
    49         p = q;
    50     }
    51     return q;
    52 }
    53 
    54 int main()
    55 {
    56     while (scanf ("%d%d", &n, &m) != EOF && n){
    57         for (int i = 0; i < n; ++ i)
    58             scanf ("%d", &a[i]);
    59         for (int i = 0; i < n; ++ i)
    60             scanf ("%d", &b[i]);
    61 
    62         printf ("%d
    ", (int)(gao()*100.0+0.5));
    63     }
    64     return 0;
    65 }
    View Code
    ------------------------------------------------------------------
    现在的你,在干什么呢?
    你是不是还记得,你说你想成为岩哥那样的人。
  • 相关阅读:
    <转>Java 高并发综合
    <转>Spring 知识点提炼
    qqq
    ttt
    工作中的那些坑(2)——逆波兰表达式
    工作中的那些坑(1)——一次过滤存量数据的优化过程
    Java学习笔记
    《代码大全》笔记(一)
    由Cocos2d-x工程入口窥见代理模式
    makefile
  • 原文地址:https://www.cnblogs.com/plumrain/p/math_01.html
Copyright © 2020-2023  润新知