题目大意:
有一张有向图,对于每个点,有两种操作:
1. 删掉它的所有入边
2. 删掉它的所有出边
对每个点的每个操作均有不同的价值。
求使得图上没有边的最小价值。
解题思路:
考虑把点拆成入点和出点,然后就是二分图最小点权覆盖集。
也可以考虑最小割。
从S到每个点的入点连容量为该点执行操作2的价值,每个点的出点到T连容量为该点执行操作1的价值。对于图上的每条边连容量inf的边。
然后答案就是最小割(割一条S出发的边,相当于执行了2操作,网络流不可能从该点再流向其他节点,则相当于删掉出边。操作1同理)。
C++ Code:
#include<bits/stdc++.h> using namespace std; const int S=0,T=10005,inf=0x3fffffff; struct edge{ int to,nxt,cap; }e[200005]; int head[10050],cnt=1,n,m,level[10050],iter[10050]; inline void addedge(int from,int to,int flow){ e[++cnt]=(edge){to,head[from],flow}; head[from]=cnt; e[++cnt]=(edge){from,head[to],0}; head[to]=cnt; } queue<int>q; void bfs(){ level[S]=1; for(q.push(S);!q.empty();){ int u=q.front(); q.pop(); for(int i=head[u];~i;i=e[i].nxt) if(e[i].cap&&!~level[e[i].to]){ level[e[i].to]=level[u]+1; q.push(e[i].to); } } } inline int min(int a,int b){return a<b?a:b;} int dfs(int u,int f){ if(!f||u==T)return f; for(int& i=iter[u];~i;i=e[i].nxt) if(e[i].cap&&level[e[i].to]>level[u]){ int d=dfs(e[i].to,min(f,e[i].cap)); if(d){ e[i].cap-=d; e[i^1].cap+=d; return d; }else level[e[i].to]=-1; } return 0; } int dinic(){ for(int flow=0,f;;){ memset(level,-1,sizeof iter); if(bfs(),!~level[T])return flow; memcpy(iter,head,sizeof iter); while(f=dfs(S,inf))flow+=f; } } int main(){ memset(head,-1,sizeof head); ios::sync_with_stdio(false);cin.tie(0); cin>>n>>m; for(int i=1;i<=n;++i){ int p; cin>>p; addedge(i+n,T,p); } for(int i=1;i<=n;++i){ int p; cin>>p; addedge(S,i,p); } while(m--){ int x,y; cin>>x>>y; addedge(x,y+n,inf); } cout<<dinic()<<endl; return 0; }