专题: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
",  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
", 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
", ans );
    }
}
Dinkelbach(150ms)

poj3621

最优比率环

大意:给定一张图,边上有花费。求一个环使得收益和/花费和最大,输出这个比值。

按照前两题的模式,应该是要求∑(a[i]-k*b[i])在一个合法解中的值。

接下来的的问题是如何求合法解,即环。假设我们将单向边对应的花费和收益对应起来,将边权更新为-(a[i]-k*b[i]),那么我们可以通过判断负环的存在判断是否存在f[k]<0.

根据这个性质就可以进行二分了。

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

const int N = 5009;
const double Eps = 1e-3;
int n, m;
int u[N], v[N], w[N], val[N];
double rat[N];
double dis[N];

bool BF ( double k )
{
    int flag ;
    for ( int i = 1; i <= m; ++i )  rat[i] = k * w[i] - val[v[i]];
    for ( int i = 1; i <= n; ++i ) dis[i] = 0;
    for ( int i = 1; i <= n; ++i ) {
        flag = 0;
        for ( int j = 1; j <= m; ++j ) {
            if ( dis[u[j]] + rat[j] < dis[v[j]] ) {
                dis[v[j]] = dis[u[j]] + rat[j];
                flag = 1;
            }
        }
        if ( !flag ) return 0;
    }
    return 1;
}

int main()
{
    scanf ( "%d %d", &n, &m );
    for ( int i = 1; i <= n; ++i ) {
        scanf ( "%d", &val[i] );
    }
    for ( int i = 1; i <= m; ++i ) {
        scanf ( "%d %d %d", &u[i], &v[i], &w[i] );
    }
    double l = 0., r = 20000;
    while ( fabs ( r - l ) > Eps ) {
        double mid = ( r + l ) / 2;
        if ( BF ( mid ) ) l = mid;
        else r = mid;
    }
    printf ( "%.2f
", l );
}
二分法
原文地址:https://www.cnblogs.com/keam37/p/4658334.html