rainyroad

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
//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\n",f(0,r));;
    return 0;
}

 

posted on 2018-11-23 18:17  rainyroad  阅读(226)  评论(0编辑  收藏  举报