A famous mobile communication company is planning to build a new set of base stations. According to the previous investigation, n places are chosen as the possible new locations to build those new stations. However, the condition of each position varies much, so the costs to built a station at different places are different. The cost to build a new station at the ith place is P i (1<=i<=n).
When complete building, two places which both have stations can communicate with each other.
Besides, according to the marketing department, the company has received m requirements. The ith requirement is represented by three integers A i, B i and C i, which means if place A i and B i can communicate with each other, the company will get C i profit.
Now, the company wants to maximize the profits, so maybe just part of the possible locations will be chosen to build new stations. The boss wants to know the maximum profits.
Input
Multiple test cases (no more than 20), for each test case:
The first line has two integers n (0< n < = 5000) and m ( 0 < m <=50000).
The second line has n integers, P1 through Pn, describes the cost of each location.
Next m line, each line contains three integers, A i, B i and C i, describes the ith requirement.
Output
One integer each case, the maximum profit of the company.
Sample Input
5 5
1 2 3 4 5
1 2 3
2 3 4
1 3 3
1 4 2
4 5 3
Sample Output
4
如果题目中有: 对于 要想做B事情 ,你必须做完A和C的 话 (并且每个点都有权值)。 对于这种的论述 ,就很有可能最大权闭合问题。
建图 模板:
S->点权为正的点
点权为负的点->T
然后就是多条类似上面条件的情况,转化一下就是 : B- >A ,B->C
这样建图,最后 最大权闭合图的权值为 :所有正权值的点权和 – 最小割(S,T)
代码
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
#include<iostream>
using namespace std;
#define LL long long
const int N = (int)6e4+11;
const int M = (int)4e5+11;
const int mod = 1e9+7;
const int inf = (int)0x3f3f3f3f;
struct Edge {
int form,to,cap,flow,nexts;
}edge[M];
int head[N],top;
void init(){
memset(head,-1,sizeof(head));
top=0;
}
void addedge(int a,int b,int c){
Edge e={a,b,c,0,head[a]};
edge[top]=e;head[a]=top++;
Edge ee={b,a,0,0,head[b]};
edge[top]=ee;head[b]=top++;
}
int vis[N],dis[N];
int cur[N];
bool bfs(int st,int ed){
queue<int>Q;
memset(vis,0,sizeof(vis));
memset(dis,-1,sizeof(dis));
Q.push(st);vis[st]=1;dis[st]=1;
while(!Q.empty()){
int now=Q.front();Q.pop();
for(int i=head[now];i!=-1;i=edge[i].nexts){
Edge e=edge[i];
if(!vis[e.to]&&e.cap-e.flow>0){
vis[e.to]=1;
dis[e.to]=dis[now]+1;
if(e.to==ed) return 1;
Q.push(e.to);
}
}
}
return 0;
}
int dfs(int now,int a,int ed){
if(a==0||now==ed) return a;
int flow=0,f;
for(int &i=cur[now];i!=-1;i=edge[i].nexts){
Edge &e=edge[i];
if(dis[e.to]==dis[now]+1&&(f=dfs(e.to,min(e.cap-e.flow,a),ed))>0){
e.flow+=f;
flow+=f;
edge[i^1].flow-=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int max_flow(int st ,int ed){
int flow=0;
while(bfs(st,ed)){
memcpy(cur,head,sizeof(head));
flow+=dfs(st,inf,ed);
}
return flow;
}
int main( ){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
int S=0,T=n+m+1; init();
for(int i=1;i<=n;i++){
int c;scanf("%d",&c);
addedge(i,T,c);
}
int ans=0;
for(int i=1;i<=m;i++){
int a,b,c; scanf("%d%d%d",&a,&b,&c);
addedge(S,n+i,c);
addedge(n+i,a,inf);
addedge(n+i,b,inf);
ans+=c;
}
printf("%d\n",ans-max_flow(S,T));
}
return 0;
}