0——1分数问题规划
Posted rainyskywx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于0——1分数问题规划的主要内容,如果未能解决你的问题,请参考以下文章