01分数规划

Posted Mychael

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了01分数规划相关的知识,希望对你有一定的参考价值。

01分数规划,就是这样一个东西
\(max(\frac{\sum ai * xi}{\sum bi * xi})\),其中\(xi \in {0,1}\)
简而言之,就是在n个物品中选出任意几个【或者可以有限制选多少个】,使得其两种权值a,b的比值最大

这样的问题可以二分解决
假如有这样一道裸题:POJ2976,选n - k个物品使得比值最大
我们二分出r,
若存在\(\frac{\sum ai * xi}{\sum bi * xi} >= r\),则r可行
变形得\(\sum ai * xi - r * \sum bi * xi >= 0\)
我们就可以把每件物品看做是权值\(ai - bi * r\),排个序看看前n - k大之和是否大于0即可

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
using namespace std;
const int maxn = 1005,maxm = 100005,INF = 1000000000;
int n,k;
double A[maxn],B[maxn],t[maxn];
bool check(double x){
    REP(i,n) t[i] = A[i] - x * B[i];
    sort(t + 1,t + 1 + n);
    double sum = 0;
    for (int i = k + 1; i <= n; i++) sum += t[i];
    return sum > 0;
}
int main(){
    while (~scanf("%d%d",&n,&k) && (n || k)){
        REP(i,n) scanf("%lf",&A[i]);
        REP(i,n) scanf("%lf",&B[i]);
        double l = 0,r = 1.0,mid;
        while (r - l > 0.0000001){
            mid = (l + r) / 2;
            if (check(mid)) l = mid;
            else r = mid;
        }
        printf("%d\n",(int)round(l * 100));
    }
    return 0;
}

以上是关于01分数规划的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ_1486_[HNOI2009]最小圈_01分数规划

01分数规划学习笔记

bzoj4753

POJ 3621 Sightseeing Cows (bellman-Ford + 01分数规划)

01分数规划

01分数规划