bzoj 1191: [HNOI2006]超级英雄Hero 网络流_残量网络

bzoj 1191: [HNOI2006]超级英雄Hero 网络流_残量网络

首先,二分肯定是可以的.

不过,我们用残量网络做更优美一些.

依次枚举每一个人,并将该人对应的边都连上.

如果每次在残量网络上都能增广出一个流量,那么就说明新加入的是可以的.

为什么在残量网络上跑是正确的呢 ? 

我们关注这个函数: 

int maxflow(){         
     memset(current,0,sizeof(current));            
     int ans=0; 
     while(BFS()) ans+=dfs(st,inf); 
     return ans; 
}    

 

这意味着,Dinic 求最大流过程中每次都是试图从起点向终点找出一条增广路. 

而每次增广出的流量是可以累加的. 

所以,在新增的残量网络上求出的流量也就可以和先前的流量累加了,互不干扰. 

Code:

#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){
        scanf("%d%d",&A[i],&B[i]);                                     
        Dinic::add(0,i,1);
        Dinic::add(i,A[i]+nex,1); C[i]=Dinic::edges.size()-2; 
        Dinic::add(i,B[i]+nex,1); D[i]=Dinic::edges.size()-2; 
        if(!check[A[i]]) Dinic::add(A[i]+nex,3000,1);       
        if(!check[B[i]]) Dinic::add(B[i]+nex,3000,1); 
        check[A[i]]=check[B[i]]=1; 
        if(Dinic::maxflow()<1) break; 
        ans=i; 
    }                        
    ans=(ans==68)?40:ans; 
    printf("%d\n",ans); 
    return 0;  
}

  

posted @ 2019-05-11 10:58 EM-LGH 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值