BZOJ-1497 [NOI2006]最大获利 最小割
题意:有n个地点可以选择是否修建,建的成本为p[i],用户有M个,对于每个用户,如果地点Ai和Bi都修了的,那么你就可以获得Ci的收益,现在问你最多能获得多少钱
题解:考虑最小割
对于每个地点 build(s,i,p[i])
对于每个用户 build(i+n,t,c[i])
他所需要的2个地点,build(a[i],i+n,inf);build(b[i],i+n,inf)
然后用总的收益减去最小割就是答案 Why?
我们想割掉的是连向s的边 表示我们修了这个地点 成本增加了
割掉的是连向t的边 表示我们没有赚到这个客户的钱 获利减少了
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 55005 4 #define M 160000 5 const int inf=0x7fffffff/3; 6 namespace Dinic 7 { 8 int head[N],head2[N],p=1; 9 struct Rec 10 { 11 int go,nex,c; 12 }eg[M*2]; 13 void build(int a,int b,int c) 14 { 15 eg[++p]=(Rec){b,head[a],-c}; 16 head[a]=p; 17 eg[++p]=(Rec){a,head[b],0}; 18 head[b]=p; 19 } 20 int dis[N],Q[N],s[N],S,T,stop,ans; 21 bool bfs() 22 { 23 memset(dis,0,sizeof(dis)); 24 dis[T]=1; 25 Q[1]=T; 26 for (int p1=1,p2=1;p1<=p2;p1++) 27 { 28 for (int i=head[Q[p1]];i;i=eg[i].nex) 29 if (eg[i^1].c<0&&!dis[eg[i].go]) 30 { 31 dis[eg[i].go]=dis[Q[p1]]+1; 32 Q[++p2]=eg[i].go; 33 } 34 } 35 if (!dis[S]) return false; 36 memcpy(head2,head,sizeof(head)); 37 return true; 38 } 39 bool dinic(int p,int top) 40 { 41 if (p==T) 42 { 43 int x=inf; 44 for (int i=1;i<=top-1;i++) if (-eg[s[i]].c<x) x=-eg[s[i]].c,stop=i; 45 for (int i=1;i<=top-1;i++) eg[s[i]].c+=x,eg[s[i]^1].c-=x; 46 ans+=x; 47 return true; 48 } 49 for (int &i=head2[p];i;i=eg[i].nex) 50 { 51 if (eg[i].c<0&&dis[eg[i].go]==dis[p]-1) 52 { 53 s[top]=i; 54 if (dinic(eg[i].go,top+1)&&top!=stop) return true; 55 } 56 } 57 return false; 58 } 59 int ask() 60 { 61 ans=0; 62 while (bfs()) dinic(S,1); 63 return ans; 64 } 65 void init(int _S,int _T){ 66 S=_S,T=_T; 67 } 68 } 69 using namespace Dinic; 70 void clear() 71 { 72 p=1; 73 memset(head,0,sizeof(head)); 74 } 75 int n,m,ss,tt,x,y,z,why; 76 int main() 77 { 78 scanf("%d%d",&n,&m); 79 ss=0;tt=n+m+1; 80 init(ss,tt); 81 for (int i=1;i<=n;i++) 82 { 83 scanf("%d",&x); 84 build(ss,i,x); 85 } 86 for (int i=1;i<=m;i++) 87 { 88 scanf("%d%d%d",&x,&y,&z); 89 why+=z; 90 build(i+n,tt,z); 91 build(y,i+n,inf); 92 build(x,i+n,inf); 93 } 94 printf("%d\n",why-ask()); 95 return 0; 96 }
Anderyi!