分數規劃模板(洛谷P4377 [USACO18OPEN]Talent Show)(分數規劃,二分答案,揹包)

分數規劃是這樣一個東西:c++

給定若干元素,每一個元素有兩個屬性值\(a_i,b_i\),在知足題目要求的某些限制下選擇若干元素並求出\(\frac{\sum a}{\sum b}\)的最大值。spa

若是沒有限制的話,確定是貪心的選。code

假設當前選擇了一個解\(x_0\),卻並非\(\frac{\sum a}{\sum b}\)的最大值,咱們有ip

\[\frac{\sum a}{\sum b}>x_0\]get

進而it

\[\sum a-bx_0>0\]class

這時候咱們要求的東西變成了\(a-bx_0\),每一個元素的貢獻就獨立了。最大化它的和,若是大於\(0\),就說明\(\frac{\sum a}{\sum b}\)的最大值比\(x_0\)還要大,反之亦然。di

因而咱們就不難想到二分了。控制\(x_0\)的上下界,每次取\(mid\)進行求值並判斷。while

例題:洛谷P4377 [USACO18OPEN]Talent Showco

此題的限制是\(\sum b\)不小於於給定值,以\(b\)的和爲下標,每選一個物品後用揹包轉移便可。複雜度\(O(nW\log na)\)

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define R RG int
#define G if(++ip==ie)fread(ip=buf,1,SZ,stdin)
using namespace std;
const LL SZ=1<<19,N=1009,INF=0xc0c0c0c0c0c0c0c0;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
int t[N],w[N];
LL f[N];
inline int in(){
    G;while(*ip<'-')G;
    R x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
inline void chkmx(RG LL&x,RG LL y){
    if(x<y)x=y;
}
int main(){
    R n=in(),W=in(),i,j,l=0,r=2500000,m;
    RG LL del;
    for(i=1;i<=n;++i)
        w[i]=in(),t[i]=in()*1000;
    while(l<r){
        m=(l+r+1)>>1;
        memset(f+1,128,W<<3);
        for(i=1;i<=n;++i){
            del=t[i]-(LL)w[i]*m;
            for(j=W;~j;--j)
                if(f[j]!=INF)chkmx(f[min(j+w[i],W)],f[j]+del);
        }
        f[W]>=0?l=m:r=m-1;
    }
    printf("%d\n",l);
    return 0;
}
相關文章
相關標籤/搜索