zoukankan      html  css  js  c++  java
  • 0——1分数问题规划

    //0/1分数规划问题
    //问题:给定a1,a2,a3,...,an;b1,b2,b3,...,bn。n对整数,从中选出若干对,使得
    //a1+。。。+an的和与b1+。。。+bn的和,两者的商最大。
    //解决方法:设商为L,则sum(a)/sum(b)=L。当sum(a)—L*sum(b)>0时
    //则等价于:sum(a)/sum(b)>L,即L的值取小了。
    //当sum(a)—L*sum(b)<0时,等价于,sum(a)/sum(b)<L,即L值选大了
     
    //问题描述:给定一个N个点,M条边的无向图(1<=N,M<=10000),图中每条边e都有一个收益Ce
    //一个成本Re。求该图的一颗生成树T,使树中各边的收益之和除以成本之和,即sum(Ce)/sum(Re)最大。 
    //思路:每一条边只有一个权值Ce-mid*Re。在新的无向图中求最大生成树
    //若最大生成树上的边权之和非负,则令l=mid,否则就令r=mid 
    
    
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #define maxn 10000+5
    using namespace std;
    int fa[maxn],n,m;
    long long ans;
    struct rec{
        int x;
        int y;
        long long Ce;
        long long Re;
        long long w;
    }edges[maxn];
    
    
    bool operator <(rec a,rec b)
    {
        return a.w>b.w;
    }
    
    
    bool find_fa(int x)
    {
        if(x==fa[x])
        return x;
        return find_fa(fa[x]);
    }
    
    
    void f2(long long mid)
    {
       for(int i=1;i<=m;i++)
       {
           edges[i].w=edges[i].Ce-mid*edges[i].Re;
        }    
    }
    
    
    /*long long sum(long long mid)
    {
        long long sum2=0;
        for(int i=1;i<=m;i++)
        {
          sum2+=edges[i].Ce-mid*Re;      
        }
        return sum2;
    }*/
    
    
    long long kruskal()
    {
        for(int i=1;i<=n;i++)
        fa[i]=i;
        sort(edges+1,edges+m);
        ans=0;
        for(int i=1;i<n;i++)
        {
        int x=find_fa(edges[i].x);
        int y=find_fa(edges[i].y);
        if(x==y)
        continue;
        fa[x]=y;
        ans+=edges[i].w;
        }
        return ans;    
    }
    
    
    long long f(long long l,long long r)
    {
        long long mid;
        long long cnt;
        while(r<l)
        {
            mid=(r+l)>>1;
            f2(mid);
            cnt=kruskal();
            if(cnt>=0)
              l=mid;
            else
              r=mid;
        }
        return mid;
    }
    
    
    int main()
    {
        long long r=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
        scanf("%d%d%d%d",&edges[i].x,&edges[i].y,&edges[i].Ce,&edges[i].Re);
        r=r+edges[i].Ce;
        }
        printf("%ll
    ",f(0,r));;
        return 0;
    }
  • 相关阅读:
    几个ID
    一百层高楼和两个棋子
    快速了解的链接 shell sed awk
    用shell实现一个“输入密码”程序
    i love you do you love me
    打造全新视觉环境
    【转】LINUX 环境变量总结
    TextBox输入限制
    获取CPU和硬盘序列号
    Lable属性设置(winform)
  • 原文地址:https://www.cnblogs.com/rainyskywx/p/10009118.html
Copyright © 2011-2022 走看看