首页 > 代码库 > bzoj 2502 清理雪道 (有源汇上下界最小流)
bzoj 2502 清理雪道 (有源汇上下界最小流)
2502: 清理雪道
Time Limit: 10 Sec Memory Limit: 128 MBDescription
滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。
Input
Output
输出文件的第一行是一个整数k – 直升飞机的最少飞行次数。
Sample Input
8
1 3
1 7
2 4 5
1 8
1 8
0
2 6 5
0
1 3
1 7
2 4 5
1 8
1 8
0
2 6 5
0
Sample Output
4
下界为1,上界为inf
法一、从超级源点向超级汇点跑一遍dinic,再由普通汇点向普通源点连一条下界为0,上界为inf的边,再由超级源点向超级汇点跑一遍dinic
答案为最后加的那条边的反向边的流量
#include<cstdio>#include<queue>#include<algorithm>#define N 105#define M 40001using namespace std;const int inf=2e9;int n,a[N],ans;int src,dec,S,T;int to[M],next[M],front[N],tot=1,cap[M];int lev[N],cur[N];queue<int>q;void add(int u,int v,int w){ to[++tot]=v; next[tot]=front[u]; front[u]=tot; cap[tot]=w; to[++tot]=u; next[tot]=front[v]; front[v]=tot; cap[tot]=0;}bool bfs(int s,int t){ for(int i=0;i<=n+3;i++) cur[i]=front[i],lev[i]=-1; while(!q.empty()) q.pop(); lev[s]=0; q.push(s); int now; while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=next[i]) if(cap[i]>0&&lev[to[i]]==-1) { lev[to[i]]=lev[now]+1; if(to[i]==t) return true; q.push(to[i]); } } return false;}int dfs(int now,int t,int flow){ if(now==t) return flow; int rest=0,delta; for(int i=front[now];i;i=next[i]) if(cap[i]>0&&lev[to[i]]>lev[now]) { delta=dfs(to[i],t,min(flow-rest,cap[i])); if(delta) { cap[i]-=delta; cap[i^1]+=delta; rest+=delta; if(rest==flow) return rest; } } if(rest!=flow) lev[now]=-1; return rest;}int dinic(int s,int t){ while(bfs(s,t)) dfs(s,t,inf); }int main(){ scanf("%d",&n); dec=n+1; S=n+2;T=n+3; for(int i=1;i<=n;i++) add(i,dec,inf); for(int i=1;i<=n;i++) add(src,i,inf); int x,y; for(int i=1;i<=n;i++) { scanf("%d",&x); while(x--) { scanf("%d",&y); add(i,y,inf); a[y]++; a[i]--; } } for(int i=1;i<=n;i++) if(a[i]>0) add(S,i,a[i]); else if(a[i]<0) add(i,T,-a[i]); dinic(S,T); add(dec,src,inf); dinic(S,T); printf("%d",cap[tot]);}
法二、先由普通汇点向普通源点连一条下界为0,上界为inf的边,再由超级源点向超级汇点跑一遍dinic,记那条边的流量为okflow
删去那条边,删去超级源点,删去超级汇点,由普通汇点向普通源点跑一遍dinic,得出最大流为a,
答案为okflow-a
#include<cstdio>#include<queue>#include<algorithm>#define N 105#define M 40001using namespace std;const int inf=2e9;int n,a[N],ans;int src,dec,S,T;int to[M],next[M],front[N],tot=1,cap[M];int lev[N],cur[N];queue<int>q;void add(int u,int v,int w){ to[++tot]=v; next[tot]=front[u]; front[u]=tot; cap[tot]=w; to[++tot]=u; next[tot]=front[v]; front[v]=tot; cap[tot]=0;}bool bfs(int s,int t){ for(int i=0;i<=n+3;i++) cur[i]=front[i],lev[i]=-1; while(!q.empty()) q.pop(); lev[s]=0; q.push(s); int now; while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=next[i]) if(cap[i]>0&&lev[to[i]]==-1) { lev[to[i]]=lev[now]+1; if(to[i]==t) return true; q.push(to[i]); } } return false;}int dfs(int now,int t,int flow){ if(now==t) return flow; int rest=0,delta; for(int i=front[now];i;i=next[i]) if(cap[i]>0&&lev[to[i]]>lev[now]) { delta=dfs(to[i],t,min(flow-rest,cap[i])); if(delta) { cap[i]-=delta; cap[i^1]+=delta; rest+=delta; if(rest==flow) return rest; } } if(rest!=flow) lev[now]=-1; return rest;}int dinic(int s,int t){ int tmp=0; while(bfs(s,t)) tmp+=dfs(s,t,inf); return tmp;}void del(int x){ for(int i=front[x];i;i=next[i]) cap[i]=cap[i^1]=0;}int main(){ scanf("%d",&n); dec=n+1; S=n+2;T=n+3; for(int i=1;i<=n;i++) add(i,dec,inf); for(int i=1;i<=n;i++) add(src,i,inf); int x,y; for(int i=1;i<=n;i++) { scanf("%d",&x); while(x--) { scanf("%d",&y); add(i,y,inf); a[y]++; a[i]--; } } for(int i=1;i<=n;i++) if(a[i]>0) add(S,i,a[i]); else if(a[i]<0) add(i,T,-a[i]); add(dec,src,inf); dinic(S,T); int okflow=cap[tot]; del(T); del(S); cap[tot]=cap[tot-1]=0; printf("%d",okflow-dinic(dec,src));}
问题:法二中,dinic得出的最大流 与 有普通汇点向普通源点 连边 的反向边的流量 为什么不相等?
printf("%d",okflow-dinic(dec,src)); ??
bzoj 2502 清理雪道 (有源汇上下界最小流)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。