01 分数规划小结

01分数规划是用来解决这样的一类问题:
有一堆物品,每一个物品有一个收益ai,一个代价bi,我们要求一个方案使选择的∑ai/∑bi最大。

这一类问题一般都有固定套路:
我们令x=∑ai/∑bi,我们要最大化x。
稍微改变一下得到:∑(ai-bi*x)>=0。
即我们需满足这个条件下得到最大的x。
那么我们就可以直接二分答案,即二分这个x的值。
这就直接是一个判定性问题了。

看一道板子:bzoj 5281 Talent Show
这个就是按上述套路,二分答案,再跑一个背包判断一下,就好了。

#include <bits/stdc++.h>
using namespace std;
inline int gi () {
    int x=0, w=0; char ch=0;
    while (! (ch>='0' && ch<='9') ) {
        if (ch=='-') w=1;
        ch=getchar ();
    }
    while (ch>='0' && ch<='9') {
        x= (x<<3) + (x<<1) + (ch^48);
        ch=getchar ();
    }
    return w?-x:x;
}

const int N=251;
int n,W,l,r=100000,Mid,wi[N],val[N];
long long f[100010];

bool Check (int Val) {
    memset (f, 0xcf, sizeof (f) );
    f[0]=0;
    for (int i=1;i<=n;++i)
        for (int j=W;j>=0;--j) {
            int k=min (j+wi[i], W);
            f[k]=max (f[k], f[j]+val[i]- (long long) wi[i]*Val);
        }
    return f[W]>=0;
}

int main ()
{
    n=gi (), W=gi ();
    for (int i=1;i<=n;++i) {
        wi[i]=gi (), val[i]=gi ();
        val[i]*=1000;
    }
    while (l<r) {
        Mid= (l+r+1) >>1;
        if (Check (Mid) ) l=Mid;
        else r=Mid-1;
    }
    printf ("%d\n", l);
    return 0;
}

另外一道板子:bzoj 4753 最佳团体
同理,二分答案+树形背包判断。

#include <bits/stdc++.h>
using namespace std;
inline int gi () {
    int x=0, w=0; char ch=0;
    while (! (ch>='0' && ch<='9') ) {
        if (ch=='-') w=1;
        ch=getchar ();
    }
    while (ch>='0' && ch<='9') {
        x= (x<<3) + (x<<1) + (ch^48);
        ch=getchar ();
    }
    return w?-x:x;
}

const int N=2510;
const double Eps=1e-5;
int n,K,tot,head[N],Size[N];
double l,r=20000,Mid,Val[N],Pay[N],f[N][N];

struct Edge {
    int next, now;
}e[N];
inline void Make (int from, int to) {
    e[++tot].next=head[from];
    head[from]=tot;
    e[tot].now=to;
}

void DP (int x) {
    Size[x]=1;
    f[x][0]=0;
    f[x][1]=Val[x]-Pay[x]*Mid;
    for (int i=head[x];i;i=e[i].next) {
        int y=e[i].now;
        DP (y);
        for (int i=Size[x];i>=1;--i)
            for (int j=Size[y];j>=0;--j)
                f[x][i+j]=max (f[x][i+j], f[x][i]+f[y][j]);
        Size[x]+=Size[y];
    }
}

bool Check () {
    memset (f, 0xc2, sizeof (f) );
       memset (Size, 0, sizeof (Size) );
    DP (0);
    if (f[0][K+1]>0) return 1;
    return 0;
}

int main ()
{
    K=gi (), n=gi ();
    for (int i=1, Pre;i<=n;++i) {
        scanf ("%lf%lf", &Pay[i], &Val[i]);
        Pre=gi ();
        Make (Pre, i);
    }
    while (r-l>=Eps) {
        Mid= (l+r) /2.0;
        if (Check () ) l=Mid;
        else r=Mid;
    }
    printf ("%.3lf\n", l);
    return 0;
}

可以发现(个人感觉huaji)01分数规划是和背包紧密相连的。。

猜你喜欢

转载自www.cnblogs.com/Bhllx/p/9821135.html