专题: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(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\n", l );

}
二分法

 

你可能感兴趣的:(规划)