二分图的最小权点覆盖问题可以使用最小割模型求解
在求具体方案的时候,首先找到割集,也就是从源点搜出去,之后判断两边访问情况求点覆盖
#include<bits/stdc++.h> using namespace std; const int N=1e5+10; const int inf=1e8; int h[N],ne[N],e[N],idx,f[N]; int S,T; int st[N]; int d[N],cur[N]; void add(int a,int b,int c){ e[idx]=b,ne[idx]=h[a],f[idx]=c,h[a]=idx++; e[idx]=a,ne[idx]=h[b],f[idx]=0,h[b]=idx++; } int bfs(){ memset(d,-1,sizeof d); d[S]=0; cur[S]=h[S]; queue<int> q; q.push(S); while(q.size()){ int t=q.front(); q.pop(); for(int i=h[t];i!=-1;i=ne[i]){ int j=e[i]; if(d[j]==-1&&f[i]){ cur[j]=h[j]; d[j]=d[t]+1; if(j==T) return true; q.push(j); } } } return false; } int find(int u,int limit){ if(u==T){ return limit; } int i; int flow=0; for(i=cur[u];i!=-1&&flow<limit;i=ne[i]){ cur[u]=i; int j=e[i]; if(d[j]==d[u]+1&&f[i]){ int t=find(j,min(f[i],limit-flow)); if(!t) d[j]=-1; else{ f[i]-=t; f[i^1]+=t; flow+=t; } } } return flow; } int dinic(){ int flow; int r=0; while(bfs()){ while(flow=find(S,inf)) r+=flow; } return r; } void dfs(int u) { st[u] = true; for (int i = h[u]; ~i; i = ne[i]) if (f[i] && !st[e[i]]) dfs(e[i]); } int main(){ ios::sync_with_stdio(false); memset(h,-1,sizeof h); int i; int n,m; cin>>n>>m; S=0,T=2*n+1; for(i=1;i<=n;i++){ int x; cin>>x; add(S,i,x); } for(i=1;i<=n;i++){ int x; cin>>x; add(i+n,T,x); } for(i=1;i<=m;i++){ int a,b; cin>>a>>b; add(b,a+n,inf); } cout<<dinic()<<endl; dfs(S); int cnt=0; for(i=0;i<idx;i+=2){ int b=e[i],a=e[i^1]; if(st[a]&&!st[b]) cnt++; } cout<<cnt<<endl; for(i=0;i<idx;i+=2){ int b=e[i],a=e[i^1]; if(st[a]&&!st[b]){ if(a==S) cout<<b<<" +"<<endl; } } for(i=0;i<idx;i+=2){ int b=e[i],a=e[i^1]; if(st[a]&&!st[b]){ if(b==T) cout<<a-n<<" -"<<endl; } } }