zoukankan      html  css  js  c++  java
  • 01分数规划

    https://blog.csdn.net/hzoi_ztx/article/details/54898323

    01分数规划问题主要包含以下几个问题:

    • 一般的01分数规划
    • 最优比率生成树
    • 最优比率环

     

    关于二分判断条件的理解。

    给出几道例题:一、POJ-2976

    入门

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <cctype>
    #include <cmath>
    #include <time.h>
    #include <map>
    #include <set>
    #include <vector>
    
    using namespace std;
    
    #define ms(a,b) memset(a,b,sizeof(a))
    
    typedef long long ll;
    
    const double eps=1e-7;
    
    int n,k;
    double a[1010],b[1010],d[1010];
    
    inline int read()
    {
        int X=0,w=0; char ch=0;
        while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    
    int main()
    {
        while (1)
        {
            n=read(),k=read();
            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]);
            double l=0.0,r=1.0,mid;
            while (r-l>eps)
            {
                mid=(l+r)/2;
                for (int i=1;i<=n;i++) d[i]=a[i]-mid*b[i];
                sort(d+1,d+1+n);
                double sum=0.0;
                for (int i=k+1;i<=n;i++) sum+=d[i];
                if (sum>0) l=mid;
                else r=mid;
            }
            printf("%.0f\n",mid*100);
        }
        return 0;
    }
    View Code

    51nod

    也是入门

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <cctype>
    #include <cmath>
    #include <time.h>
    #include <map>
    #include <set>
    #include <vector>
    
    using namespace std;
    
    #define ms(a,b) memset(a,b,sizeof(a))
    
    typedef long long ll;
    
    const int maxn = 50005;
    
    const double eps = 1e-9;
    
    ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
    
    struct node
    {
        int w,p;
        double val;
        bool operator < (const node& T) const{
            return val>T.val;
        }
    }b[maxn];
    
    double mid;
    ll anss,ansx,tmps,tmpx;
    int n,k;
    
    bool check()
    {
        int tot=0;
        for(int i=0;i<n;i++)b[i].val = 1.0*b[i].p-b[i].w*mid;
        sort(b,b+n);
        double sum=0;
        tmps=0,tmpx=0;
        for(int i=0;i<k;i++)sum+=b[i].val,tmps+=b[i].p,tmpx+=b[i].w; 
        if(sum-0>=eps)return true;
        return false;
    }
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++) scanf("%d%d",&b[i].w,&b[i].p);
        double l=0,r=500000;
        for(int i=0;i<100;i++)
        {
            mid=(l+r)/2;
            if(check())l=mid,anss=tmps,ansx=tmpx;
            else r=mid;
        }
        ll tmp=gcd(anss,ansx);
        anss/=tmp,ansx/=tmp;
        printf("%lld/%lld\n",anss,ansx);
        return 0;
    }
    View Code

    POJ - 2728(最优比率生成树)

    大意:给定一张图,每条边有一个收益值和一个花费值, 求一个生成树,要求花费/收益最小,输出这个值
    分析:现在的限制就有点复杂了,要求解必须是一棵生成 树。而且这道题目要求的花费/收益最小,当然你求收益/ 花费最大然后反过来也是可以的,注意处理花费为0的情 况。如果求最小的,处理方法是也类似的,先求个D,然 后做一次最小生成树,显然得到的就是函数值。

    POJ-3621(最优比率环)

    大意:给定一张图,边上有花费,点上有收益,点可以多 次经过,但是收益不叠加,边也可以多次经过,但是费用 叠加。求一个环使得收益和/花费和最大,输出这个比值。
    分析:比上面更加的恶心了。先不说环的问题,就是花费 和收益不在一处也令人蛋疼。这时候需要用到几个转化和 结论。
    首先的一个结论就是,不会存在环套环的问题,即最优的方 案一定是一个单独的环,而不是大环套着小环的形式。这个的 证明其实非常的简单,大家可以自己想一下(提示,将大环上 的收益和记为x1,花费为y1,小环上的为x2,y2。重叠部分的花 费为S。表示出来分类讨论即可)。有了这个结论,我们就可以 将花费和收益都转移到边上来了,因为答案最终一定是一个环, 所以我们将每一条边的收益规定为其终点的收益,这样一个环 上所有的花费和收益都能够被正确的统计。
    解决了蛋疼的问题之后,就是01分数规划的部分了,我们只 需要计算出D数组后找找有没有正权环即可,不过这样不太好, 不是我们熟悉的问题,将D数组全部取反之后,问题转换为查找 有没有负权环,用spfa或是bellman_ford都可以。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define N 100010
    using namespace std;
    const double eps=1e-5;
    struct edge
    {
        int v,nxt,w;
        double c;
    } e[N<<1];
    int head[N],f[N];
    bool vis[N];
    double dis[N];
    int n,m,mct,u,v,w;
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    void add(int u,int v,int w)
    {
        e[++mct].v=v;e[mct].nxt=head[u];e[mct].w=w;head[u]=mct;
    }
    bool spfa(int u)
    {
        vis[u]=1;
        for(int i=head[u]; i; i=e[i].nxt)
        {
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].c)
            {
                dis[v]=dis[u]+e[i].c;
                if(vis[v] || spfa(v))
                {
                    vis[v]=0;
                    return 1;
                }
            }
        }vis[u]=0;return 0;
    }
    void judge(double r)
    {
        for(int i=1; i<=mct; i++)
            e[i].c=(double)e[i].w*r-f[e[i].v];
        return;
    }
    bool check()
    {
        for(int i=1; i<=n; i++)
            if(spfa(i))return 1;
        return 0;
    }
    int main()
    {
        n=read();m=read();
        for(int i=1; i<=n; i++) f[i]=read();
        for(int i=1; i<=m; i++)
        {
            u=read();v=read();w=read();
            add(u,v,w);
        }
        double l=0,r=100000,ans;
        while(r-l>eps)
        {
            double mid=(l+r)/2;
            judge(mid);
            if(check())
            {
                ans=mid;l=mid;
            }
            else r=mid;
        }
        printf("%.2f\n",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    华为交换机中hybrid、access、trunk的区别
    debug调试
    网络基础--ICMP
    HCNA---ARP协议
    Python之字典
    python之元组
    网络基础--Telnet、SSH、FTP
    学习Cisco切换为华为的第一天---Telnet
    学思科,考华为,用华三。这是多少人的现况,快来听听我的经历~
    [P3385]【模板】负环 (spfa / bellman-ford)
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/13668906.html
Copyright © 2011-2022 走看看