• 专题: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 );
    }
    二分法
  • 相关阅读:
    on() 和 click() 的区别
    net core swagger
    sgen.exe 未能运行
    SQL Server 动态行转列(参数化表名、分组列、行转列字段、字段值)
    net core 实现简单爬虫—抓取博客园的博文列表
    javascript基础 方法
    android通过httpClient请求获取JSON数据并且解析
    发布到IIS的时候用户 'WWW-6743CC520E9ASPNET' 登录失败
    WebServices生成发布过程及常见问题的解决方法
    Android、iPhone和Java三个平台一致的加密工具
  • 原文地址:https://www.cnblogs.com/keam37/p/4658334.html
Copyright © 2020-2023  润新知