AcWing2325 有向图破坏(最小权点覆盖)

二分图的最小权点覆盖问题可以使用最小割模型求解

在求具体方案的时候,首先找到割集,也就是从源点搜出去,之后判断两边访问情况求点覆盖

#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;
        }
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13627597.html