[笔记乱写]0/1分数规划

第一次写这类blog?其实早就想把知识总结一下但是真的没有时间啊喂

感觉这东西比较实用且简易所以口胡一篇

 

所谓分数规划,就是求最优比率,比如一个分数的最大值。

经典模型:

给定若干对整数$a_i,b_i$,要求从中选出几对,使$\frac{\sum a_i}{\sum b_i}$最大。

对于这个问题,我们不妨xjb猜随意选取一个值$L$,然后考虑:

是否存在一组解,满足$\sum a_i-L*b_i \ge 0$

把上面那个鬼畜柿子化一下,可得$\sum a_i-\sum L*b_i \ge 0$,

最终变成$\frac{\sum a_i}{\sum b_i}\ge L$

那如果符合条件的解存在的话,就说明存在比L更大的比率,即L比我们所求的最大值要小。

那要是不存在呢?L比最大值还大呗。

是不是很熟悉?这玩意显然可以二分答案搞吧,因为L与解的关系存在单调性。

那么怎么判定$\sum a_i-L*b_i \ge 0$是否有解呢?算一下$\sum a_i-L*b_i$的最大值看它正负不就好了。

这很好求啊,因为$a_i-L*b_i$可以直接算的,只要看一下哪些取哪些不取就能得道最值了。

 

所以遇到这类问题直接二分答案,判断$\sum a_i-mid*b_i$的最大值是否非负,是就l=mid,否则r=mid(一定要注意实数范围二分与整数二分的不同)

最后的l就是最优比例。

 

丢一道例题[bzoj4753]最优团体

挺裸的分数规划,不过check需要做树上依赖背包,每次拍成dfs序$O(nK)$dp即可。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=2505;
const double eps=1e-5,inf=19260817.233;
int K,n,fa[N];
double now[N],dp[N][N],w[N],val[N],maxx=-inf;
int to[N<<1],nxt[N<<1],head[N],tot;
int dfn[N],rev[N],num,size[N];
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
void add(int x,int y)
{
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
void dfs(int x)
{
    size[x]=1;
    dfn[x]=num;
    rev[num++]=x;
    for(int i=head[x];i;i=nxt[i])
        dfs(to[i]),size[x]+=size[to[i]];
}
double DP(double x)
{
    for(int i=1;i<=n;i++)
        now[i]=val[rev[i]]-x*w[rev[i]];
    for(int i=1;i<=n+1;i++)
        for(int j=0;j<=K+1;j++)
            dp[i][j]=-inf;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=min(i,K+1);j++)
            dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]+now[i]),
            dp[i+size[rev[i]]][j]=max(dp[i+size[rev[i]]][j],dp[i][j]);
    return dp[n+1][K+1];
}
int main()
{
    K=read();n=read();
    for(int i=1;i<=n;i++)
    {
        w[i]=(double)read();
        val[i]=(double)read(),maxx=max(maxx,val[i]);
        fa[i]=read();
        add(fa[i],i);
    }
    dfs(0);
    double l=0.0,r=maxx;
    while(r-l>eps)
    {
        double mid=(l+r)/2.0;
        if(DP(mid)>=eps)l=mid;
        else r=mid;
    }
    printf("%.3lf",l);
    return 0;
}
View Code

 

posted @ 2019-08-02 21:29  Rorschach_XR  阅读(155)  评论(1编辑  收藏  举报
//雪花飘落效果