Loading

分数规划

普通01分数规划

由n个物品,每个物品由两个属性a和b,选出k个物品,使Σai / Σbi 的值最大

设x=Σai / Σbi, F()=Σa-xΣb, D()=a-xb

当F()=0时,则为答案;当F()>0时,则说明答案小了;当F()<0时,则说明答案大了

二分答案

double l=0,r=1.0,mid;
while(r-l>1e-5) {
    mid=(l+r)/2;
    if(work(mid)) l=mid;
    else r=mid;
}
int work(double x) {
    for(int i=0;i<n;i++) d[i]=a[i]-x*b[i];
    sort(d,d+n);
    double F=0;
    for(int i=n-1;i>=n-k;i--) F+=d[i];
    return F>=0;
}

 


 

最优比率生成树

带权无向图G,对于每条边有vali,costi。现在求一棵生成树T,最大(小)化val / cost。

二分答案,对边赋值w=val-r*cost,有选前|G|-1条大的w,即求最大生成树,套用01分数规划的模板。

例题:http://poj.org/problem?id=2728 

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
#define maxn 1050
#define inf 0x7fffffff
static double eps=1e-4;
int vis[maxn],x[maxn],y[maxn],z[maxn],p[maxn];
double d[maxn],cost[maxn][maxn],dis[maxn][maxn];
int n;
double prim(double x) {
    double totcost=0,totdis=0;
    double sum=0.0;
    for(int i=1;i<=n;i++) p[i]=1;
    d[1]=0;
    memset(vis,0,sizeof(vis)); vis[1]=1;
    for(int i=2;i<=n;i++) d[i]=cost[1][i]-dis[1][i]*x;

    int k;
    for(int i=2;i<=n;i++) {
        double mincost=inf;
        for(int j=2;j<=n;j++) {
            if(!vis[j] && d[j]<mincost) {
                mincost=d[j];
                k=j;
            }
        }
        vis[k]=1;
        sum+=mincost;
        totcost+=cost[p[k]][k];
        totdis+=dis[p[k]][k];
        for(int j=1;j<=n;j++) {
            if(!vis[j] && d[j]>cost[k][j]-dis[k][j]*x) {
                d[j]=cost[k][j]-dis[k][j]*x;
                p[j]=k;
            }
        }
    }
//    return totcost/totdis; ///二分
    return sum; ///迭代
}
int main( ) {
    while(scanf("%d",&n),n) {
        for(int i=1;i<=n;i++) {
            scanf("%d%d%d",&x[i],&y[i],&z[i]);
            for(int j=1;j<i;j++) {
                double tmp=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
                cost[i][j]=cost[j][i]=abs(z[i]-z[j]);
                dis[i][j]=dis[j][i]=sqrt(tmp);
            }
        }
        double a=0;
//        while(1) {
//            double b=prim(a);
//            if(abs(a-b)<eps) {
//                printf("%.3f\n", a);
//                break;
//            }
//            else a=b;
//        }
        ///迭代
        double head=0,tail=100000.0;
        while(tail-head>1e-5) {
            double mid=(head+tail)/2.0;
            a=prim(mid);
            if(a>=0) head=mid;
            else tail=mid;
        }
        printf("%.3f\n", tail);
    }
    return 0;
}
View Code

 


 

最优比率生成环

给定有点权和边权的图,求一个环,使得环的点权和与边权和的比值最大。

01分数规划+树形背包

posted @ 2019-10-02 22:56  qinuna  阅读(182)  评论(0编辑  收藏  举报