bzoj1497

来源:互联网 发布:模拟外汇交易软件 编辑:程序博客网 时间:2024/04/29 16:53

要求最大获利

如果我能使损失的收益最小,那么就是最大获利了。

把每一个中转站看成一个点,用户群也看成一个点

源向中转站连边,容量为建中转站的费用

用户群向汇连边,容量为收益

如果用户群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);}


1 0
原创粉丝点击