BZOJ 2502 清理雪道

来源:互联网 发布:淘宝网总裁张杰 编辑:程序博客网 时间:2024/05/17 22:04

上下界最小流

网络上退流的算法没弄懂,于是我就按照论文里面说二分+最大流判定

论文:《一种简易的方法求解流量有上下界的网络中网络流》(没有超链- -)

#include<cstdio>#include<cstring>#include<algorithm>#define N 105#define S 101#define T 102#define SS 103#define TT 104 using namespace std;struct edge{int next,to,flow;}e[N*N*5];const int INF = 1<<29;int last[N], cur[N], ecnt=1, deg[N], q[N], level[N];void add(int a, int b, int c){    e[++ecnt]=(edge){last[a],b,c};    last[a]=ecnt;    e[++ecnt]=(edge){last[b],a,0};    last[b]=ecnt;}  bool bfs(){    memset(level,0,sizeof(level));    q[0]=SS;    level[SS]=1;    for(int head=0, tail=1; head<tail; head++)    {        int x=q[head];        for(int i = last[x]; i; i=e[i].next)        {            int y=e[i].to;            if(e[i].flow==0 || level[y])continue;            level[y]=level[x]+1;            if(y==TT)return true;            q[tail++]=y;        }    }    return false;}int dfs(int x, int mx){    if(x==TT || !mx)return mx;    int use=0;    for(int &i = cur[x]; i; i=e[i].next)    {        int y=e[i].to;        if(level[x]+1!=level[y])continue;        int w = dfs(y,min(mx-use,e[i].flow));        e[i].flow-=w;        e[i^1].flow+=w;        use+=w;        if(use==mx)return mx;    }    return use;}void dinic(){    while(bfs())    {        memcpy(cur,last,sizeof(last));        dfs(SS,INF);    }}bool check(int lim){    for(int i = 2; i < ecnt; i+=2)    {        e[i].flow+=e[i^1].flow;        e[i^1].flow=0;    }    e[ecnt-1].flow=lim;    dinic();    for(int i = last[SS]; i; i=e[i].next)        if(e[i].flow)return false;    return true;}int main(){    int n;    scanf("%d",&n);    for(int i = 1, m, to; i <= n; i++)    {        scanf("%d",&m);        deg[i]+=m;        while(m--)        {            scanf("%d",&to);            deg[to]--;            add(i,to,INF);         }    }    for(int i = 1; i <= n; i++)    {        add(S,i,INF);        add(i,T,INF);        if(deg[i]<0)            add(SS,i,-deg[i]);        if(deg[i]>0)            add(i,TT,deg[i]);    }    add(T,S,0);    int l = 0, r = n*n;    while(l<r)    {        int mid=(l+r)>>1;        if(check(mid))r=mid;        else l=mid+1;    }    printf("%d\n",l);}
0 0
原创粉丝点击