[有上下界最小流] BZOJ2502: 清理雪道

来源:互联网 发布:北京消费者网络投诉 编辑:程序博客网 时间:2024/05/21 06:20

题意

滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。
n<=100

题解

题目抽象出来就是用最少的路径数覆盖一个DAG,即每条边至少经过一次。
直接搞成有源汇有上下界的最小流即可,建图很简单:
S–>i 容量无限大,i–>T 容量无限大
i–>j 容量[1,+]
然后就好了。

#include<cstdio>#include<queue>#include<cstring>#include<algorithm>using namespace std;const int maxn=1005,maxe=200005;struct Edge{    int from,to,flow,cap;    Edge(int t1=0,int t2=0,int t3=0,int t4=0){ from=t1; to=t2; flow=t3; cap=t4; }} Es[maxe];int fir[maxn],nxt[maxe],tot=1;void add(int x,int y,int z){    Es[++tot]=Edge(x,y,0,z); nxt[tot]=fir[x]; fir[x]=tot;    Es[++tot]=Edge(y,x,0,0); nxt[tot]=fir[y]; fir[y]=tot;}queue <int> que;int S,T,SS,TT,N,d[maxn],tmp[maxn];int n,ans0;bool Bfs(int S,int T){    memset(d,63,sizeof(d)); int INF=d[0];    while(!que.empty()) que.pop();     que.push(S); d[S]=0;     while(!que.empty()){        int x=que.front(); que.pop();        for(int j=fir[x];j;j=nxt[j]) if(d[Es[j].to]==INF&&Es[j].cap>Es[j].flow){            d[Es[j].to]=d[x]+1; que.push(Es[j].to);        }    }    return d[T]!=INF;}int pos[maxn];int find_Dfs(int x,int flow,int T){    if(x==T||flow==0) return flow;    int res=0,t;    for(int &j=pos[x];j;j=nxt[j]){        if(d[x]+1==d[Es[j].to]&&(t=find_Dfs(Es[j].to,min(flow,Es[j].cap-Es[j].flow),T))>0){            Es[j].flow+=t; Es[j^1].flow-=t;             res+=t; flow-=t; if(flow==0) break;        }    }    return res;}int Dinic(int S,int T){    int MaxFlow=0;    while(Bfs(S,T)){        for(int i=1;i<=N;i++) pos[i]=fir[i];         MaxFlow+=find_Dfs(S,1e+9,T);    }    return MaxFlow;}void Del(int x){    for(int j=fir[x];j;j=nxt[j]) Es[j].flow=Es[j].cap=Es[j^1].flow=Es[j^1].cap=0;} int main(){    freopen("bzoj2502.in","r",stdin);    freopen("bzoj2502.out","w",stdout);    scanf("%d",&n);    N=n; S=++N; T=++N; SS=++N; TT=++N;    for(int i=1;i<=n;i++){        int t,x; scanf("%d",&t);        while(t--){            scanf("%d",&x);            add(i,x,1e+9); tmp[i]--; tmp[x]++;        }    }    for(int i=1;i<=n;i++) add(S,i,1e+9), add(i,T,1e+9);    for(int i=1;i<=n;i++){        if(tmp[i]>0) add(SS,i,tmp[i]);                else add(i,TT,-tmp[i]);    }    add(T,S,1e+9);    Dinic(SS,TT); ans0=Es[tot-1].flow+0;    Es[tot].cap=Es[tot].flow=Es[tot-1].cap=Es[tot-1].flow=0; Del(SS); Del(TT);    printf("%d\n",ans0-Dinic(T,S));    return 0;}
原创粉丝点击