【洛谷P4843】清理雪道

费用流

题目大意:

给定一张有向无环图,用最少的链覆盖它。

题解:

每条边都要被经过一次,那么就是有一个 $1$ 的流量下界。

建图以后,跑最小费用可行流即可。

Code:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=120,inf=0x3f3f3f3f;
struct edge{
    int to,nxt,cap,cost;
}e[50000];
int head[N],dlt[N],cnt=1,ans,n,iter[N],dis[N],S,T,TT;
bool vis[N];
inline void addedge(int u,int v,int cap,int cost){
    e[++cnt]=(edge){v,head[u],cap,cost},head[u]=cnt;
    e[++cnt]=(edge){u,head[v],0,-cost},head[v]=cnt;
}
inline void AddEdgE(int u,int v,int L,int R){
    dlt[v]+=L,dlt[u]-=L,addedge(u,v,R-L,0);
}
int dfs(int u,int f){
    if(!f||u==TT)return f;
    vis[u]=1;
    int ret=0;
    for(int&i=iter[u];i;i=e[i].nxt)
    if(e[i].cap&&!vis[e[i].to]&&dis[e[i].to]==dis[u]+e[i].cost){
        int d=dfs(e[i].to,min(f,e[i].cap));
        e[i].cap-=d,e[i^1].cap+=d,f-=d,ret+=d;
        if(!f)break;
    }
    vis[u]=0;
    return ret;
}
bool MCMF(){
    memset(dis,0x3f,sizeof dis);
    *dis=0;
    static queue<int>q;
    for(q.push(0);!q.empty();){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt)
        if(e[i].cap&&dis[e[i].to]>dis[u]+e[i].cost){
            dis[e[i].to]=dis[u]+e[i].cost;
            if(!vis[e[i].to])vis[e[i].to]=1,q.push(e[i].to);
        }
    }
    if(dis[TT]>1e9)return 0;
    memcpy(iter,head,sizeof head);
    ans+=dis[TT]*dfs(0,inf);
    return 1;
}
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n;S=n+1,T=S+1,TT=T+1;
    for(int i=1;i<=n;++i){
        addedge(S,i,inf,1);
        int k,x;
        cin>>k;
        while(k--)cin>>x,AddEdgE(i,x,1,inf);
        addedge(i,T,inf,0);
    }
    addedge(T,S,inf,0);
    for(int i=1;i<=T;++i)
    if(dlt[i]>0)addedge(0,i,dlt[i],0);else
    if(dlt[i]<0)addedge(i,TT,-dlt[i],0);
    while(MCMF());
    cout<<ans<<'\n';
    return 0;
}