P4843 清理雪道(上下界网络流)

P4843 清理雪道

上下界最小流

我们先搞一遍上下界可行流(转)

回忆上下界最大流的写法:在可行流的残量网络$s\ -\ t$上跑最大流,答案为可行流$+$残量网络的最大流

那么上下界最小流的写法呢?

只要在残量网络$t\ -\ s$上跑最大流,答案就是可行流$-$残量网络$t\ -\ s$的最大流辣

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define N 1005
#define M 1000005
const int inf=2e9;
int n,S,T,pS,pT,ex[N],d[N],cur[N];
queue <int> h; bool vis[N];
int cnt=1,hd[N],nxt[M],ed[N],poi[M],val[M],fr[M];
inline void adde(int x,int y,int v){
    nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt,
    ed[x]=cnt, poi[cnt]=y, val[cnt]=v, fr[cnt]=x;
}
inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);}
inline void ins(int x,int y,int l,int r){link(x,y,r-l),ex[x]-=l,ex[y]+=l;}
bool bfs(){
    for(int i=1;i<=pT;++i) vis[i]=0,cur[i]=hd[i];
    h.push(S); vis[S]=1;
    while(!h.empty()){
        int x=h.front(); h.pop();
        for(int i=hd[x];i;i=nxt[i]){
            int to=poi[i];
            if(!vis[to]&&val[i]>0)
                d[to]=d[x]+1,vis[to]=1,h.push(to);
        }
    }return vis[T];
}
int dfs(int x,int a){
    if(x==T||a==0) return a;
    int F=0,f;
    for(int &i=cur[x];i;i=nxt[i]){
        int to=poi[i];
        if(d[to]==d[x]+1&&(f=dfs(to,min(a,val[i])))>0)
            a-=f,F+=f,val[i]-=f,val[i^1]+=f;
        if(!a) break;
    }return F;
}
int dinic(){int re=0; while(bfs())re+=dfs(S,inf);return re;}
void del(int x){for(int i=hd[x];i;i=nxt[i])val[i]=val[i^1]=0;}
int main(){
    scanf("%d",&n); int tt,pi;
    S=n+1; T=S+1; pS=T+1; pT=pS+1;
    for(int i=1;i<=n;++i){
        ins(S,i,0,inf);
        ins(i,T,0,inf);
        scanf("%d",&tt);
        while(tt--) scanf("%d",&pi),ins(i,pi,1,inf);
    }
    for(int i=1;i<=T;++i){//调整
        if(ex[i]<0) link(i,pT,-ex[i]);
        if(ex[i]>0) link(pS,i,ex[i]);
    }link(T,S,inf);//T向S连inf,使流量守恒
    int tmps=S,tmpt=T;
    S=pS; T=pT; dinic();
    int Flow=val[cnt]; val[cnt]=val[cnt-1]=0;//可行流的大小即为(T,S,inf)的反向边的流量
    S=tmpt; T=tmps; del(pS); del(pT);//倒着跑最大流
    printf("%d",Flow-dinic());
    return 0;
}

 

转载于:https://www.cnblogs.com/kafuuchino/p/10804443.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值