1. 程式人生 > >0——1分數問題規劃

0——1分數問題規劃

namespace ret 一個 define mes 最大 oid ... +=

//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; }

0——1分數問題規劃