bzoj 1191: [HNOI2006]超级英雄Hero 网络流 + 残量网络
题目描述:
现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的
多少获得不同数目的奖品或奖金。主持人问题准备了若干道题目,只有当选手正确回答一道题后,才能进入下一题
,否则就被淘汰。为了增加节目的趣味性并适当降低难度,主持人总提供给选手几个“锦囊妙计”,比如求助现场
观众,或者去掉若干个错误答案(选择题)等等。这里,我们把规则稍微改变一下。假设主持人总共有m道题,选
手有n种不同的“锦囊妙计”。主持人规定,每道题都可以从两种“锦囊妙计”中选择一种,而每种“锦囊妙计”
只能用一次。我们又假设一道题使用了它允许的锦囊妙计后,就一定能正确回答,顺利进入下一题。现在我来到了
节目现场,可是我实在是太笨了,以至于一道题也不会做,每道题只好借助使用“锦囊妙计”来通过。如果我事先
就知道了每道题能够使用哪两种“锦囊妙计”,那么你能告诉我怎样选择才能通过最多的题数吗?
题解:
首先,二分肯定是可以的.
不过,我们用残量网络做更优美一些.
依次枚举每一个人,并将该人对应的边都连上.
如果每次在残量网络上都能增广出一个流量,那么就说明新加入的是可以的.
为什么在残量网络上跑是正确的呢 ?
我们关注这个函数:
int maxflow(){ memset(current,0,sizeof(current)); int ans=0; while(BFS()) ans+=dfs(st,inf); return ans; }
这意味着,Dinic 求最大流过程中每次都是试图从起点向终点找出一条增广路.
而每次增广出的流量是可以累加的.
所以,在新增的残量网络上求出的流量也就可以和先前的流量累加了,互不干扰.
最后,一定特判一下重边的情况!!!
Code:
// luogu-judger-enable-o2 // luogu-judger-enable-o2 // luogu-judger-enable-o2 // luogu-judger-enable-o2 #include<bits/stdc++.h> #define maxn 100000 #define inf 20000 #define setIO(s) freopen(s".in","r",stdin) #define nex 1303 using namespace std; int A[maxn],B[maxn]; namespace Dinic{ int st,ed; struct Edge{ int from,to,cap; Edge(int u,int v,int c):from(u),to(v),cap(c){}; }; vector<Edge>edges; vector<int>G[maxn]; void add(int u,int v,int c){ edges.push_back(Edge(u,v,c)); edges.push_back(Edge(v,u,0)); int m=edges.size(); G[u].push_back(m-2); G[v].push_back(m-1); } int d[maxn],vis[maxn],current[maxn]; queue<int>Q; int BFS(){ memset(vis,0,sizeof(vis)); d[st]=0,vis[st]=1; Q.push(st); while(!Q.empty()) { int u=Q.front(); Q.pop(); int sz=G[u].size(); for(int i=0;i<sz;++i){ Edge r = edges[G[u][i]]; if(r.cap>0 && !vis[r.to]) { vis[r.to]=1,d[r.to]=d[u]+1; Q.push(r.to); } } } return vis[ed]; } int dfs(int x,int cur){ if(x==ed) return cur; int f,flow=0; for(int v=G[x].size(),i=current[x];i<v;++i){ current[x]=i; Edge r = edges[G[x][i]]; if(r.cap>0 && d[r.to]==d[x]+1) { f=dfs(r.to,min(cur,r.cap)); cur-=f,flow+=f; edges[G[x][i]].cap-=f,edges[G[x][i]^1].cap+=f; } if(cur==0) break; } return flow; } int maxflow(){ memset(current,0,sizeof(current)); int ans=0; while(BFS()) ans+=dfs(st,1); return ans; } void re(){ edges.clear(); for(int i=0;i<maxn;++i) G[i].clear(); memset(current,0,sizeof(current)); memset(d,0,sizeof(d)); memset(vis,0,sizeof(vis)); } }; int C[maxn],D[maxn]; int check[maxn]; int main(){ // setIO("input"); int n,m; scanf("%d%d",&n,&m); int ans=0; Dinic::st=0,Dinic::ed=3000; for(int i=1;i<=m;++i) Dinic::add(0,i,1); for(int i=0;i<n;++i) Dinic::add(i+nex,3000,1); for(int i=1;i<=m;++i){ scanf("%d%d",&A[i],&B[i]); Dinic::add(i,A[i]+nex,1), C[i]=Dinic::edges.size()-2; if(A[i]!=B[i]) Dinic::add(i,B[i]+nex,1); if(Dinic::maxflow()<1) break; ans=i; } printf("%d\n",ans); for(int i=1;i<=ans;++i) { if(Dinic::edges[C[i]].cap==0) printf("%d\n",A[i]); else printf("%d\n",B[i]); } return 0; }