bzoj 2502 清理雪道 - 带下界最小流

学习笔记所讲。

#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define db double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define N 1000010
#define M 1000010
#define INF 10000000
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct edges{
    int to,pre,resf;
}e[M];int h[N],etop,lev[N],cur[N],frms[N];queue<int> q;
inline int add_edge(int u,int v,int f) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop,e[etop].resf=f; }
inline int build_edge(int u,int v,int f) { return add_edge(u,v,f),add_edge(v,u,0); }
inline int build_edge(int u,int v,int lw,int up) { return frms[v]+=lw,frms[u]-=lw,(up!=lw?build_edge(u,v,up-lw):0); }
inline bool bfs(int s,int t,int n)
{
    memset(lev,0,sizeof(int)*(n+1));
    while(!q.empty()) q.pop();q.push(s),lev[s]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=h[x],y;i;i=e[i].pre)
            if(e[i].resf&&!lev[y=e[i].to])
                lev[y]=lev[x]+1,q.push(y);
    }
    return lev[t]>0;
}
int dfs(int s,int t,int a)
{
    if(s==t||!a) return a;int flow=0,f;
    for(int &i=cur[s];i;i=e[i].pre)
        if(lev[e[i].to]==lev[s]+1&&(f=dfs(e[i].to,t,min(a,e[i].resf)))>0)
        {   e[i].resf-=f,e[((i-1)^1)+1].resf+=f,a-=f,flow+=f;if(!a) break;  }
    return flow;
}
inline int dinic(int s,int t,int n,int flow=0)
{   while(bfs(s,t,n)) memcpy(cur,h,sizeof(int)*(n+1)),flow+=dfs(s,t,INF);return flow;   }
int main()
{
    int n=inn(),s=n+1,t=s+1;
    rep(x,1,n) for(int k=inn();k;k--) build_edge(x,inn(),1,INF);
    int ss=t+1,tt=ss+1,tot=0;build_edge(t,s,INF);
    rep(i,1,n) build_edge(s,i,0,INF),build_edge(i,t,0,INF);
    rep(i,1,n)
        if(frms[i]>0) build_edge(ss,i,frms[i]),tot+=frms[i];
        else build_edge(i,tt,-frms[i]);
    if(dinic(ss,tt,tt)^tot) return assert(0),0;
    for(int i=h[t];i;i=e[i].pre) if(e[i].to==s)
        tot=INF-e[i].resf,e[i].resf=e[((i-1)^1)+1].resf=0;
    return !printf("%d\n",tot-dinic(t,s,tt));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值