传送门
最大权闭合子图入门题。
把点的花费看成负权值,跟汇点连边: ( i , p i ) (i,p_i) (i,pi)=> ( i , t , p i ) (i,t,p_i) (i,t,pi)
对于边 ( u , v , w ) (u,v,w) (u,v,w),连 ( s , n e w n o d e , w ) , ( n e w n o d e , u , i n f ) , ( n e w n o d e , v , i n f ) (s,newnode,w),(newnode,u,inf),(newnode,v,inf) (s,newnode,w),(newnode,u,inf),(newnode,v,inf)
然后跑最大权闭合子图即可。
代码:
#include
#define N 200005
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,m,ans=0,tot;
struct edge{int v,c,next;};
struct Dinic{
int first[N],cur[N],s,t,cnt,d[N];
edge e[N<<1];
inline void init(){cnt=-1,memset(first,-1,sizeof(first)),s=0,t=N-5;}
inline void addedge(int u,int v,int c){e[++cnt].v=v,e[cnt].next=first[u],e[cnt].c=c,first[u]=cnt;}
inline void add(int u,int v,int c){addedge(u,v,c),addedge(v,u,0);}
inline bool bfs(){
queue<int>q;
memset(d,-1,sizeof(d)),q.push(s),d[s]=0;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=first[x];~i;i=e[i].next){
int v=e[i].v;
if(!e[i].c||~d[v])continue;
d[v]=d[x]+1,q.push(v);
}
}
return ~d[t];
}
inline int dfs(int x,int f){
if(!f||x==t)return f;
int flow=f;
for(int i=first[x];~i;i=e[i].next){
int v=e[i].v;
if(!flow)break;
if(d[v]==d[x]+1&&e[i].c){
int tmp=dfs(v,min(flow,e[i].c));
if(!tmp)d[v]=-1;
e[i].c-=tmp,e[i^1].c+=tmp,flow-=tmp;
}
}
return f-flow;
}
inline int solve(){
int ret=0;
while(bfs())ret+=dfs(s,0x3f3f3f3f);
return ret;
}
}dinic;
int main(){
n=read(),m=read(),dinic.init(),tot=n;
for(int i=1,p;i<=n;++i)dinic.add(i,dinic.t,read());
for(int a,b,c,i=1;i<=m;++i){
++tot,a=read(),b=read(),ans+=(c=read());
dinic.add(tot,a,0x3f3f3f3f),dinic.add(tot,b,0x3f3f3f3f),dinic.add(dinic.s,tot,c);
}
cout<<ans-dinic.solve();
return 0;
}