[bzoj2502]清理雪道——带有下界的最小流 大佬们的博客 Some Links

题目大意:

给定一个DAG图,一次操作可以沿着DAG图的方向遍历所有能够到达的边,要求把所有的边都遍历完毕,每一条边可以遍历多次,求最小操作次数。

思路:

乍一看好像是一个模型?为什么感觉和之间做的最小链覆盖很像?然后打了一会之后才发现最小链覆盖是在点上面的,而这一道题目是覆盖边,然后那个模型就没有办法用了。
让我们来科学理性地建立模型,即每一个边都至少要遍历一次。假设从 A 一直走到 B 可以一次做完的话,那么就可看做是一条从 A B 的流量为1的一条流。这么转化过来之后我们要求的似乎就是每一条边满足1的下界的全图的最小流,每一个点都向源汇点 s , t 连边,这个时候只要套最小流的板子就好了。

最小流的做法是借用了循环流的方法,既然我们是要在DAG上面求最小流量,那么只要从 t > s 连一条边,跑完循环流之后 t > s 这条边的流量就是全图的流量。有一个地方需要注意的是,这样跑出来的不一定是最小流,虽然在循环流中它的流量最少,但是一旦某一条流量多余地经过了一些边,按照这种方法计算的流量则变大了,所以最后还要再反向跑一次最大流来推流,最后相减即可。

/*=============================
 * Author : ylsoi
 * Problem : bzoj2502
 * Algorithm : Min_Flow
 * Time : 2018.7.29
 * ==========================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("bzoj2502.in","r",stdin);
    freopen("bzoj2502.out","w",stdout);
}

const int maxn=100+10;
const int maxm=1e4+10;
const int inf=0x3f3f3f3f;
int n,m,a[maxn],ans,s,t,ss,tt,sumf;
int cnte=1,beg[maxn],to[maxm<<1],las[maxm<<1],flow[maxm<<1];

void add(int u,int v,int f){
    las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; flow[cnte]=f;
    las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; flow[cnte]=0;
}

struct dinic{
    int num[maxn],cur[maxn];
    queue<int>qu;
    bool bfs(){
        memset(num,0,sizeof(num));
        num[ss]=1; qu.push(ss);
        while(qu.size()){
            int u=qu.front(); qu.pop();
            for(int i=beg[u];i;i=las[i]){
                if(!flow[i] || num[to[i]])continue;
                num[to[i]]=num[u]+1;
                qu.push(to[i]);
            }
        }
        return num[tt]!=0;
    }
    int dfs(int u,int res){
        if(u==tt || !res)return res;
        int ret=0,f;
        for(int &i=cur[u];i;i=las[i]){
            if(num[to[i]]!=num[u]+1)continue;
            if((f=dfs(to[i],min(res,flow[i])))){
                res-=f;
                ret+=f;
                flow[i]-=f;
                flow[i^1]+=f;
            }
            if(!res)break;
        }
        return ret;
    }
    void work(){
        while(bfs()){
            REP(i,ss,tt)cur[i]=beg[i];
            sumf+=dfs(ss,inf);
        }
    }
}T;

int main(){
    File();
    scanf("%d",&n);
    s=n+1; t=n+2;
    ss=0; tt=n+3;
    REP(i,1,n){
        int siz,v;
        scanf("%d",&siz);
        m+=siz;
        REP(j,1,siz){
            scanf("%d",&v);
            --a[i]; ++a[v];
            add(i,v,inf);
        }
    }

    REP(i,1,n)add(s,i,inf),add(i,t,inf);
    REP(i,1,n)if(a[i]>0)add(ss,i,a[i]);
    else add(i,tt,-a[i]);
    add(t,s,inf);
    T.work(); sumf=0;
    ans=flow[cnte];

    beg[ss]=0; beg[tt]=0;
    REP(i,1,n)beg[i]=las[beg[i]];
    beg[s]=las[beg[s]]; beg[t]=las[beg[t]];
    add(ss,t,inf); add(s,tt,inf);
    T.work();
    printf("%d\n",ans-sumf);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81267722