要求最大获利
如果我能使损失的收益最小,那么就是最大获利了。
把每一个中转站看成一个点,用户群也看成一个点
源向中转站连边,容量为建中转站的费用
用户群向汇连边,容量为收益
如果用户群i需要j和k中转站,那么j,k向i连边,容量为无限大。
求出最小割
源到站j,k,用户i到汇这三条边是不会同时割掉的,因为不可能同时损失这两者的收益
为什么
因为他们中间有容量无限大的边,这边是不会割的,所以只有可能割两端
#include<cstdio>
#include<cstdlib>
#include<cstring>
struct mod{int x,y,c,next,other;};
mod q[400005];
int first[100005];
int h[100005];
int t[100005];
int len=0,S,T;
void ins(int x,int y,int c)
{
len++;
q[len].x=x;
q[len].y=y;
q[len].c=c;
q[len].next=first[x];
first[x]=len;
q[len].other=len+1;
len++;
q[len].x=y;
q[len].y=x;
q[len].c=0;
q[len].next=first[y];
first[y]=len;
q[len].other=len-1;
}
int mymin(int u1,int u2)
{
if (u1<u2)return u1;
return u2;
}
bool set_h()
{
int st=1,ed=2;
memset(h,0,sizeof(h));
h[S]=1;
t[1]=S;
while(st<ed)
{
int x=t[st];
for (int i=first[x];i!=-1;i=q[i].next)
{
int y=q[i].y;
if (q[i].c>0&&h[y]==0)
{
h[y]=h[x]+1;
t[ed]=y;
ed++;
}
}
st++;
}
if (h[T]==0)return false;
return true;
}
int findf(int x,int f)
{
if (x==T)return f;
int s=0;
for (int i=first[x];i!=-1;i=q[i].next)
{
int y=q[i].y;
if (q[i].c>0&&h[y]==h[x]+1&&s<f)
{
int o=findf(y,mymin(f-s,q[i].c));
s+=o;
q[i].c-=o;
q[q[i].other].c+=o;
}
}
if (s==0)h[x]=0;
return s;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
T=n+m+1;
memset(first,-1,sizeof(first));
len=0;
int ans=0,num=0;
for (int i=1;i<=n;i++)
{
int p;
scanf("%d",&p);
ins(S,i,p);
}
for (int i=1;i<=m;i++)
{
int A,B,C;
scanf("%d%d%d",&A,&B,&C);
ins(A,i+n,999999999);
ins(B,i+n,999999999);
ins(i+n,T,C);
ans+=C;
}
while(set_h()==true)
{
num+=findf(S,999999999);
}
printf("%d\n",ans-num);
}