<01分数规划>淬炼神体

前言

听说教主有一次在 ACM 里面速A了一题最优比率生成树问题,然而后面许多人跟风失败….算了还是好好学习,天天向上, Orz 教主吧。

题意

给你n对数 a[i],b[i] ,让你取m对,使得 a[i]b[i] 最大。

数据范围

对于100%的数据,2≤K≤N≤100000,1≤a,b≤1000

分析

数学分析中一个很重要的方法就是分析目标式,这样我们来看目标式。

R=(a[i]x[i])/(b[i]x[i])
这时可以设一个函数 f(L)=a[i]x[i]b[i]x[i]L 让这个式子尽量接近原式 R
那么这时可以设f(L)>0,a[i]x[i]b[i]x[i]L>0
移项 a[i]x[i]>b[i]x[i]L
再转成 (a[i]x[i])/(b[i]x[i]) 的形式:
(a[i]x[i])/(b[i]x[i])>L
这时很明显L越大,则答案 (a[i]x[i])/(b[i]x[i]) 越大。(注意要保证 f(l)>0
这就是二分法了,去二分L,再去验证 f(L) 是否大于 0 ,且这时的方案x[i]就可以先排个序(因为我们要使 f(L) 的值尽量的大)这时就可以不用理 x[i] ,直接变成了 (a[i])/(b[i])
模型:

二分法
L:=…;R:=…;
Repeat
Mid:=(L+R)/2;
For I=1..X do D[i]:=A[i]-Mid*B[i];//根据Mid计算D数组
if 检查(Mid)成功 then L:=Mid else R:=Mid;
Until abs(L-R)

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=100005;
int i,n,m,a[N],b[N];
double d[N],an,l,r,mid;
int main(){
    scanf("%d %d",&n,&m);
    fo(i,1,n) scanf("%d",&a[i]);
    fo(i,1,n) {scanf("%d",&b[i]);}
    l=1;r=N;
    while (r-l>0.00001) {
          mid=(l+r)/2*1.0;
          fo(i,1,n) d[i]=a[i]-mid*b[i];
          sort(d+1,d+n+1);an=0;
          fd(i,n,n-m+1) an=an+d[i];
          if (an>0) l=mid; else r=mid;
    }
    printf("%.3lf",(l+r)/2*1.0);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值