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 }

 

posted @ 2018-09-28 11:43  口香糖万岁  阅读(162)  评论(0编辑  收藏  举报