分数规划

分数规划用来求一个分式的极值。

形式化地,给定 \(a_i,b_i\),求 \(w_i\) 使得

\[\frac{\sum\limits_{i=1}^na_i\times w_i}{\sum\limits_{i=1}^nb_i\times w_i} \]

取到最值。

求解

二分。

一下以求最大值为例。二分 mid,然后在 check 中有:

\[\begin{aligned} &\frac{\sum_{i=1}^n a_i\times w_i}{\sum_{i=1}^n b_i\times w_i}>mid\\ \Longrightarrow&\sum\limits_{i=1}^n a_i\times w_i-mid\times \sum\limits_{i=1}^n b_i\cdot w_i>0\\ \Longrightarrow&\sum\limits_{i=1}^n w_i\times(a_i-mid\times b_i)>0 \end{aligned} \]

那么只要求出不等号左边的式子的最大值就行了。如果最大值比 \(0\) 要大,说明 mid 是可行的,否则不可行。

const int N=1e5+5;
int n;
double a[N],b[N];

inline bool chk(double x){
    double s=0;
    for(int i=1;i<=n;i++)
        if(a[i]-x*b[i]>0)
            s+=a[i]-mid*[i];
   	return s>0;
}

signed main(){
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    for(int i=1;i<=n;i++)
        b[i]=read();
   	double l=0,r=1e9;
   	while(r-l>eps){
        double mid=(l+r)/2;
        if(chk(mid))
            l=mid;
        else
            r=mid;
    }
    printf("%.8lf",l);
    return 0;
}

限制选择数量

POJ 2976

把第 \(i\) 个物品的权值设为 \(a_i-mid\times b_i\),然后选最大的 \(n-k\) 个。

inline bool chk(double x){
    double s=0;
    for(int i=1;i<=n;i++)
        c[i]=a[i]-mid*b[i];
    sort(c+1,c+1+n);
    for(int i=n;i>k;i--)
        s+=c[i];
   	return s>0;
}

限制分母

luogu P4377

考虑 01 背包,将 \(b_i\) 设为第 \(i\) 个物品的重量,\(a_i-mid\times b_i\) 设为第 \(i\) 个物品的价值,\(dp_{n,w}\) 即为答案。

inline bool chk(int x){
    fill(f+1,f+1+w,-inf);
    for(int i=1;i<=n;i++)
        for(int j=w;j>=0;j--){
            int k=min(w,j+b[i]);
            f[k]=max(f[k],f[j]+a[i]-mid*b[i]);
        }
    return f[w]>0;
}

最优比率生成树

POJ 2728

将边权设为 \(a_i-mid\times b_i\)​ 然后跑 MST 即可。

最优比率环

luogu P3199

将所有边权 \(-mid\),跑 spfa 判负环即可。

inline bool spfa(int u,double x){
    vis[u]=1;
    for(auto[v,w]:G[u]){
        if(dis[v]>dis[u]+w-x){
            dis[v]=dis[u]+w-x;
            if(vis[v] or spfa(v,x))
                return true;
        }
    }
	vis[u]=0;
	return false;
}

inline bool chk(double x){
    fill(vis+1,vis+1+n,0);fill(dis+1,dis+1+n,0);
    for(int i=1;i<=n;i++)
        if(spfa(i,x))
            return true;
    return false;
}
posted @ 2024-09-19 21:05  QcpyWcpyQ  阅读(1)  评论(0编辑  收藏  举报