/**//* Amber《最小割》 题意:n个中转站,每个站建立花费Xi m个客户,每个客户需要中转站Ai,Bi,获得收益为Ci 问最大收益 要满足客户i,必须有中转站Ai,Bi(前提),就是一个闭合图了! 每个客户i作为一个节点分别向相应中转站Ai,Bi连有向边,容量INF 源点s向每个客户连边,容量为收益Ci 每个中转站向汇点t连有向边,容量为建站花费Xi
那么答案就是 总收益-最小割(割边总和) 用户群与必要的中转站是一个闭合图,问题就是选与不选了
选的话,就是S集合了,不选就是T集合了 s到T集合、S集合到t都是割边 选,则需要建站花费,即S集合到t的边 不选,则损失利益,即s到T集合的边 要使最大,肯定是割边和最小,就是最小割了 */ #include<cstdio> #include<cstring>
const int MAXN = 55010; const int INF = 1000000000;
inline int min(int a,int b){return a<b?a:b;}
struct Edge { int v,cap; Edge *next,*pair; }edge[MAXN*10];
struct Graph { Edge *E[MAXN],*cur[MAXN]; Edge *pE; int dist[MAXN],num[MAXN]; int n,s,t; bool found; void init(int nn,int ss,int tt) { n=nn; s=ss; t=tt; memset(E,0,sizeof(Edge*)*n); pE=edge; } void add(int u,int v,int cap,Edge *pair) { pE->v=v; pE->cap=cap; pE->pair=pair; pE->next=E[u]; E[u]=pE++; } void add(int u,int v,int cap) { add(u,v,cap,pE+1); add(v,u,0,pE-1); } int aug(int u,int preCap) { if(u==t) { found=true; return preCap; } int leftCap=preCap; for(Edge *&it=cur[u];it;it=it->next) { if(it->cap&&dist[u]==dist[it->v]+1) { int d=aug(it->v,min(it->cap,leftCap)); leftCap-=d; it->cap-=d; it->pair->cap+=d; if(dist[s]==n||leftCap==0)return preCap-leftCap; if(found)break; } } if(!found)//没有dist[v]+1=dist[u]时才调整 { int minD=n; for(Edge *it=E[u];it;it=it->next) { if(it->cap)minD=min(minD,dist[it->v]+1); } if(--num[dist[u]]==0)dist[s]=n; else num[dist[u]=minD]++; cur[u]=E[u]; } return preCap-leftCap; } int sap() { memset(dist,0,sizeof(int)*n); memset(num,0,sizeof(int)*n); memmove(cur,E,sizeof(Edge*)*n); num[0]=n; int flow=0; while(dist[s]<n) { found=false; flow+=aug(s,INF); } return flow; } }graph;
int main() { //freopen("in","r",stdin); //freopen("out","w",stdout); int n,m,T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); int s=0,t=n+m+1; graph.init(n+m+2,s,t); for(int i=1,x;i<=n;i++) { scanf("%d",&x); graph.add(m+i,t,x); } int ans=0; for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); ans+=c; graph.add(s,i,c); graph.add(i,m+a,INF); graph.add(i,m+b,INF); } printf("%d\n",ans-graph.sap()); } return 0; }
|