51nod 1257 背包问题 V3

题目
题解
01分数规划

0-1 分数规划
     t1 * x1 + t2 * x2 + ... + tn * xn
 r = ---------------------------------
     c1 * x1 + c2 * x2 + ... + cn * xn
给定t[1..n], c[1..n], 求x[1..n]使得sigma(xi)=k且r最大(小). 
为了让r最大, 先设计子问题z(r) = (t1 * x1 + .. + tn * xn) - r * (c1 * x1 + .. + cn * xn);
假设r的最优值为R. 则有:
z(r) < 0 当且仅当 r > R;
z(r) = 0 当且仅当 r = R;
z(r) > 0 当且仅当 r < R;
于是可二分求R.
#include<bits/stdc++.h>
using namespace std;
typedef double D;
const int N=50002;
const D eps=1e-6;
struct node{
    int p,w;
    D c;
}a[N];
int n,k,i,G,x,y,xx,yy;
D l,r,mid;
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
    int x=0,fl=1;char ch=gc();
    for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
    for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
    return x*fl;
}
bool cmp(node a,node b){
    return a.c>b.c;
}
bool check(int &x,int &y,D p){
    for (int i=0;i<n;i++) a[i].c=a[i].p-p*a[i].w;
    nth_element(a,a+k-1,a+n,cmp);
    x=0;y=0;D z=0;
    for (int i=0;i<k;i++){
        x+=a[i].p;y+=a[i].w;
        z+=a[i].c;
    }
    return z>=0;
}
int main(){
    n=read();k=read();
    for (i=0;i<n;i++) a[i].w=read(),a[i].p=read();
    l=0;r=2e9;
    while (r-l>eps){
        mid=(l+r)/2;
        if (check(x,y,mid)) l=mid,xx=x,yy=y;
        else r=mid;
    }
    G=__gcd(xx,yy);
    xx/=G;yy/=G;
    printf("%d/%d",xx,yy);
}

猜你喜欢

转载自blog.csdn.net/xumingyang0/article/details/80967497