gift 分数规划的最大权闭合子图

时间:2021-06-20 03:17:42

题目大意:

N个物品,物品间有M组关系,每个物品有一个ai的代价,满足关系后会得到bi的值

求 max(sigma(bi)/sigma(ai))

题解:

很明显的最大权闭合子图,只不过需要处理分数.

这里二分一个答案g

然后直接求sigma(b[i])-sigma(a[i]*g)即可

其中把图中的ai都改成ai*g即可

注意整数处理

 #include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
using namespace std;
const int N=,M=,INF=2e8;
int n,m;double SUM=,ep=0.0000001;
int gi(){
int str=;char ch=getchar();
while(ch>'' || ch<'')ch=getchar();
while(ch>='' && ch<='')str=(str<<)+(str<<)+ch-,ch=getchar();
return str;
}
int val[N];
struct node{
int x,y,v;
}c[M];
int head[(N+M)],num=;
struct Lin{
int next,to;double dis;
}a[(N+M)<<];
void init(int x,int y,double dis){
a[++num].next=head[x];
a[num].to=y;a[num].dis=dis;
head[x]=num;
a[++num].next=head[y];
a[num].to=x;a[num].dis=;
head[y]=num;
}
int S=,T,q[N+M],dep[N+M];
bool bfs(){
for(int i=;i<=T;i++)dep[i]=;
q[]=S;dep[S]=;
int t=,sum=,u,x;
while(t!=sum){
t++;x=q[t];
for(RG int i=head[x];i;i=a[i].next){
u=a[i].to;
if(dep[u] || a[i].dis<ep)continue;
dep[u]=dep[x]+;
q[++sum]=u;
}
}
return dep[T];
}
double dinic(int x,double tot){
if(x==T || !tot)return tot;
int u;double tmp,sum=;
for(RG int i=head[x];i;i=a[i].next){
u=a[i].to;
if(a[i].dis<ep || dep[u]!=dep[x]+)continue;
tmp=dinic(u,min(tot,a[i].dis));
a[i].dis-=tmp;a[i^].dis+=tmp;
sum+=tmp;tot-=tmp;
if(!tot)break;
}
if(sum<ep)dep[x]=;
return sum;
}
double maxflow(){
double tot=,tmp;
while(bfs()){
tmp=dinic(S,INF);
while(tmp>=ep)tot+=tmp,tmp=dinic(S,INF);
}
return tot;
}
void Clear(){
num=;
memset(head,,sizeof(head));
}
bool check(double g){
Clear();
T=n+m+;
for(RG int i=;i<=n;i++)init(S,i,g*(double)val[i]);
for(RG int i=;i<=m;i++){
init(c[i].x,i+n,INF);
init(c[i].y,i+n,INF);
init(i+n,T,c[i].v);
}
double pap=maxflow();
pap=SUM-pap;
if(pap>=ep)return true;
return false;
}
void work(){
n=gi();m=gi();
for(RG int i=;i<=n;i++)val[i]=gi();
for(RG int i=;i<=m;i++)c[i].x=gi(),c[i].y=gi(),c[i].v=gi(),SUM+=c[i].v;
double l=,r=SUM,mid,ans;
while(l<=r){
mid=(l+r)/;
if(check(mid)){
ans=mid;
l=mid+ep;
}
else r=mid-ep;
}
printf("%d\n",(int)ans);
}
int main()
{
freopen("gift.in","r",stdin);
freopen("gift.out","w",stdout);
work();
return ;
}