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;  
}

  

posted @ 2019-05-11 10:58  EM-LGH  阅读(202)  评论(0编辑  收藏  举报