A graph gives n vertices m edges, and each vertex and edge have corresponding weights. If you spend 2 vertices, you can get the weights of edges between 2 vertices, ask for the maximum profit possible.
Create a two-part graph. The left side is the right side of the base station, the edge is the edge, the source stream is all the points, and the edge right is the cost of building the base station;
In the original figure, the knots corresponding to the two Base Stations of each edge flow toward the knots corresponding to the edge, and the edge weight is not poor; all the edges correspond
And edge weight is the benefit of this edge.
When looking for the shortest cut, for each edge, do you want to cut down Z? Do you want to cut down x + y? The largest stream will help us find the most
Small cut method. We can add all the benefits and then subtract the smallest cut ~ The table contains the following meanings:
If X + Y is cut off, I will build these two bases and get the benefit of Z-(x + y; if Z is cut off, the table shows that I discard this
And get z-z is also 0.
#include <cstdio>#include <cstring>#pragma comment(linker, "/STACK:1024000000,1024000000") const int maxn=80000;const int inf=0x7fffffff;const int s=0; struct edge{ int v,next,w;}edge[1000000];int head[2*maxn],cnt;//for sapvoid addedge(int u, int v, int w){ edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].w=0; edge[cnt].next=head[v]; head[v]=cnt++;}int sap(int t){ int pre[2*maxn],cur[2*maxn],dis[2*maxn],gap[2*maxn]; int flow=0 , aug=inf ,u; bool flag; for (int i=0 ; i<=t ; ++i) { cur[i]=head[i]; gap[i]=dis[i]=0; } gap[s]=t+1; u=pre[s]=s; while (dis[s]<=t) { flag=0 ; for (int &j=cur[u] ; ~j ; j=edge[j].next) { int v=edge[j].v; if (edge[j].w>0 && dis[u]==dis[v]+1) { flag=1; if(edge[j].w<aug)aug=edge[j].w; pre[v]=u; u=v; if (u==t) { flow+=aug; while (u!=s) { u=pre[u]; edge[cur[u]].w-=aug; edge[cur[u]^1].w+=aug; } aug=inf; } break; } } if (flag)continue ; int mindis=t+1; for (int j=head[u]; ~j ; j=edge[j].next) { int v=edge[j].v; if (edge[j].w>0 && dis[v]<mindis) { mindis=dis[v]; cur[u]=j; } } if(--gap[dis[u]]==0)break; gap[dis[u]=mindis+1]++; u=pre[u]; } return flow;}void init (){ memset (head , -1 , sizeof(head)); cnt=0;}int main (){ int n,m; int u,v,w; int sum; //freopen ("0.in","r",stdin); //freopen ("tt.out","w",stdout); while (~scanf("%d%d",&n,&m)) { init(); for (int i=1 ; i<=n ; ++i) { scanf("%d",&w); addedge(0,i,w); } sum=0; for (int i=1 ; i<=m ; ++i) { scanf("%d%d%d",&u,&v,&w); addedge(u,i+n,inf); addedge(v,i+n,inf); addedge(i+n,m+n+1,w); sum+=w; } printf("%d\n",sum-sap(m+n+1)); } return 0;}