专题:01分数规划

poj2976

普通的01分数规划

大意:给定A数组B数组,从中选择N-K个使得R最大,输出Round(100*R);

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;

const int N = 1009;
const double Eps = 1e-7;
int n, k;
double a[N], b[N];
double l, r, mid;
int main() {
    while ( scanf ( "%d %d", &n, &k ) != EOF ) {
        if ( n == 0 && k == 0 ) break;
        for ( int i = 1; i <= n; ++i ) {
            scanf ( "%lf", &a[i] );
        }
        for ( int i = 1; i <= n; ++i ) {
            scanf ( "%lf", &b[i] );
        }
        l = 0., r = 1.;
        double t[N], sum;
        while ( fabs ( r - l ) > Eps ) {
            sum = 0;
            mid = 1.* ( l + r ) / 2;
            for ( int i = 1; i <= n; ++i ) {
                t[i] = 1.*a[i] - mid * b[i];
            }
            sort ( t + 1, t + 1 + n );
            for ( int i = k + 1; i <= n; ++i ) {
                sum += t[i];
            }
            if ( sum > 0 ) {
                l = mid;
            } else {
                r = mid;
            }
        }
        printf ( "%.0f\n",  100 * l );
    }
}

二分法

poj2728

最优比率生成树

大意:给定一张图,每条边有一个收益值和一个花费值,求一个生成树,要求花费/收益最小,输出这个值

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;

const int N = 1009;
const double Eps = 1e-4;
int n, k;
double x[N], y[N], h[N];
double dis[N][N], dh[N][N];
double prim ( double k )
{
    int vis[N] = {0, 1}, s = 1, u = 1, v;
    double c[N], sum = 0.;

    while ( s < n ) {
        double tem = 0x7fffffff;
        for ( int i = 1; i <= n; ++i ) {
            if ( !vis[i] ) {
                double bit = dh[u][i] - k * dis[u][i];
                if ( bit < c[i] || u == 1 ) {
                    c[i] = bit;
                }
                if ( tem > c[i] ) {
                    tem = c[i];
                    v = i;
                }
            }
        }
        sum += c[v];
        vis[v] = 1;
        u = v;
        ++s;
    }
    return sum;
}

int main()
{
    while ( scanf ( "%d", &n ) != EOF ) {
        if ( n == 0 ) break;
        for ( int i = 1; i <= n; ++i ) {
            scanf ( "%lf %lf %lf", &x[i], &y[i], &h[i] );
        }
        for ( int i = 1; i <= n; ++i ) {
            for ( int j = i + 1; j <= n; ++j ) {
                dis[i][j] = dis[j][i] = sqrt ( ( x[i] - x[j] ) * ( x[i] - x[j] ) + ( y[i] - y[j] ) * ( y[i] - y[j] ) );
                dh[i][j] = dh[j][i] = fabs ( h[i] - h[j] );
            }
        }
        double l = 0., r = 10000.0;
        while ( fabs ( r - l ) > Eps ) {
            double mid = ( l + r ) / 2;
            if ( prim ( mid ) >= 0 ) l = mid;
            else r = mid;
        }
        printf ( "%0.3f\n", l );
    }
}

二分法(700ms)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;

const int N = 1009;
const double Eps = 1e-4;
int n, k;
double x[N], y[N], h[N];
double dis[N][N], dh[N][N];
double prim ( double k )
{
    int vis[N] = {0, 1},pos[N]={0}, s = 1, u = 1, v;
    double c[N];
    double cost = 0., len = 0.;
    while ( s < n ) {
        double tem = 0x7fffffff;
        for ( int i = 1; i <= n; ++i ) {
            if ( !vis[i] ) {
                double bit = dh[u][i] - k * dis[u][i];
                if ( u == 1 || bit < c[i] ) {
                    c[i] = bit;
                    pos[i]=u;
                }
                if ( tem > c[i] ) {
                    tem = c[i];
                    v = i;
                }
            }
        }
        cost += dh[pos[v]][v], len += dis[pos[v]][v];
        vis[v] = 1;
        u = v;
        ++s;
    }
    return cost / len;
}

int main()
{
    while ( scanf ( "%d", &n ) != EOF ) {
        if ( n == 0 ) break;
        for ( int i = 1; i <= n; ++i ) {
            scanf ( "%lf %lf %lf", &x[i], &y[i], &h[i] );
        }
        for ( int i = 1; i <= n; ++i ) {
            for ( int j = i + 1; j <= n; ++j ) {
                dis[i][j] = dis[j][i] = sqrt ( ( x[i] - x[j] ) * ( x[i] - x[j] ) + ( y[i] - y[j] ) * ( y[i] - y[j] ) );
                dh[i][j] = dh[j][i] = fabs ( h[i] - h[j] );
            }
        }
        double ans = 0., k;
        while ( 1 ) {
            k = prim ( ans );
            if ( fabs ( k - ans ) < Eps ) break;
            ans = k;
        }
        printf ( "%0.3f\n", ans );
    }
}

Dinkelbach(157ms)

poj3621

时间: 2024-10-13 05:41:28

专题:01分数规划的相关文章

$POJ$2728 $Desert\ King$ 01分数规划

正解:01分数规划 解题报告: 传送门! 感觉挺板子的,,, 因为还没做,先瞎口胡一个做法$QAQ$ 如果翻车了请当做没看见我如果错了等$get$正确做法会重新编辑的$QAQ$ 就因为有$n\leq 100$,于是如果把它联成一个完全图边数连$1e4$都没有 所以考虑直接连成一个完全图,就成了之前寒假考试题二分专题那次的$T1$辽,就直接无脑01分数规划+最大生成树就欧克 $over$? 原文地址:https://www.cnblogs.com/lqsukida/p/10827485.html

01分数规划模板

/* 01分数规划模板(Dinkelbach) 01分数规划就是把 sum(a)/sum(b)转换成 f(x)=sum(a)-ans*sum(b); 当f(x)取到0时,ans取到了最大(小)值 poj 2976 两个长度为n的数组a,b 可以除去m个,怎样选择才能使剩下的 sum(a)/sum(b)的百分数最大 */ int n,m; struct Node{ int a,b; double v; ///用于排序筛选较大的值(题目要求极大值 bool operator<(const Node&am

poj3621 Sightseeing Cows --- 01分数规划

典型的求最优比例环问题 参考资料: http://blog.csdn.net/hhaile/article/details/8883652 此题中,给出每个点和每条边的权值,求一个环使 ans=∑点权/∑边权 最大. 因为题目要求一个环,而且必然是首尾相接的一个我们理解的纯粹的环,不可能是其他样子的环, 所以我们可以把一条边和指向的点看做整体处理. 上面方程可以化为:ans×e[i]-p[i]=0 以它为边权二分答案,spfa求负环,有负环则该ans可行,增大下界. 若一直不可行,则无解. #i

【Earthquake, 2001 Open 】 0-1 分数规划

71  奶牛施工队一场地震把约翰家园摧毁了,坚强的约翰决心重建家园.约翰已经修复了 N 个牧场,他需要再修复一些道路把它们连接起来.碰巧的是,奶牛们最近也成立了一个工程队,专门从事道路修复.而然,奶牛们很有经济头脑,如果无利可图,它们是不会干的.约翰和奶牛达成了协议,约翰向奶牛支付 F 元,奶牛负责修路,但不必修复所有道路,只要确保所有牧场连通即可.可供奶牛选择修复的道路有 M 条,第 i 条道路连接第 Ui 个牧场和第 Vi 个牧场,修复需要 Ti 分钟,支出成本为 Ci.保证连通所有牧场的道

编程之美第一篇 01分数规划

01分数规划 01分数规划问题其实就是解决单价之类的问题,假设给你n个物品,让你找出选k个物品的最大单价:例如南阳oj:Yougth的最大化:解决这类问题可以用二分查找,这类问题跟二分极大化最小值,极小化最大值有一些相似的地方,均是从结果出发,来进行二分查找:例如上面南阳那道题,可以转化一下: 由于v/w=单价:所以v=w*单价:即v-w*单价=0:有了这个关系,我们马上可以想到二分来查找这个值: 那么我们可以定义一个count数组来记录v-w*单价的值:由于选k个只需要把count从大到小排下

zoj 2676 Network Wars(最小割,01分数规划)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 大致题意:给出一个带权无向图,每条边有一个边权wi,求将S和T分开的一个割边集C,使得该割边集的平均边权最小,即最小化∑wi / |C| . 详见amber关于最小割模型的论文 思路:amber论文中详细讲解了如何转化成函数及建图,值得注意的是当边被重新赋权后,对于wi < 0 的边权,该边必然在最小割中,不必再建边,直接加入最大流中即可,因为求最小割时边权都为正值

zoj2676--Network Wars(0-1分数规划+最小割)

zoj2676:题目链接 题目大意:有一个n个点的网络,其中有m条光缆(所有的点都被连接,任意两个点之间最多有一条,不存在连接自身的),每条光缆有一定的价值,网络中1为起点,n为终点,现在要求找出一些光缆能分割开1到n,使它们不能相互通信,并且要求花费的和除以光缆数的值最小.输出选择的光缆的编号. 从问题中可以看出一定是0-1分数规划的题目,假设选出光缆的集合M,M为原图的一个割,光缆si∈M,价值为ci,数量k = 1 ,可以推出g(x) = min( ∑c - x*∑k ),因为si是割中的

[POJ 2728]Desert King(0-1分数规划/最优比率生成树)

Description David the Great has just become the king of a desert country. To win the respect of his people, he decided to build channels all over his country to bring water to every village. Villages which are connected to his capital village will be

BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, 对于一棵子树维护点的dep,dis,并用队列q存下来.令mx[i]表示当前dep为i的最大权值,维护一个单调队列dq,维护当前符合条件的mx,当我们从q的队尾向前扫时,它的dep是递减的,利用这个性质维护单调队列,最后更新一遍mx.具体看代码吧TAT 代码: #include<cstring>#