bzoj 1497: [NOI2006]最大获利

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define M 100008
 5 #define inf 2139062143
 6 using namespace std;
 7 int T,head[M],next[10*M],u[10*M],v[10*M],d[M],n,m,cnt=1,ans,q[2*M],sum;
 8 void jia(int a1,int a2,int a3)
 9 {
10     cnt++;
11     u[cnt]=a2;
12     v[cnt]=a3;
13     next[cnt]=head[a1];
14     head[a1]=cnt;
15 }
16 bool bfs()
17 {
18     memset(d,0,sizeof(int)*(T+2));
19     int h=0,t=1;
20     q[1]=0;
21     d[0]=1;
22     for(;h<t;)
23       {
24         h++;
25         int p=q[h];
26         for(int i=head[p];i;i=next[i])
27           if(!d[u[i]]&&v[i])
28             {
29                 d[u[i]]=d[p]+1;
30                 if(d[T])
31                   return 1;
32                 t++;
33                 q[t]=u[i];
34             }
35       }
36     return 0;
37 }
38 int dinic(int s,int f)
39 {
40     if(s==T)
41       return f;
42     int rest=f;
43     for(int i=head[s];i&&rest;i=next[i])
44       if(v[i]&&d[u[i]]==d[s]+1)
45         {
46             int now=dinic(u[i],min(rest,v[i]));
47             if(!now)
48               d[u[i]]=0;
49             v[i]-=now;
50             v[i^1]+=now;
51             rest-=now;
52         }
53     return f-rest;  
54 }
55 int main()
56 {
57     scanf("%d%d",&n,&m);
58     T=n+m+1;
59     for(int i=1;i<=n;i++)
60       {
61         int a1;
62         scanf("%d",&a1);
63         jia(i,T,a1);
64         jia(T,i,0);
65       }
66     for(int i=1;i<=m;i++)
67       {
68         int a1,a2,a3,a4;
69         a3=n+i;
70         scanf("%d%d%d",&a1,&a2,&a4);
71         sum+=a4;
72         jia(a3,a1,inf);
73         jia(a1,a3,0);
74         jia(a3,a2,inf);
75         jia(a2,a3,0);
76         jia(0,a3,a4);
77         jia(a3,0,0);
78       }
79     for(;bfs();)
80       ans+=dinic(0,inf);
81     printf("%d
",sum-ans);
82     return 0;
83 }

最小割 站向汇点连容量为费用的边,源点向用户群连容量为获利的边,用户群与站之间有关联的连容量为inf的边,跑最小割,用总收益减去即为答案。

原文地址:https://www.cnblogs.com/xydddd/p/5271180.html