[bzoj1191][HNOI2006]超级英雄Hero

题意:有n个锦囊妙计,m道题。先从第1道题做起,每道题都有两个妙计可以解决,解决之后才能进入下一题,每个妙计只能用一次,求最多能解决多少题

题解:二分答案+网络流check

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define S 0
#define T 2001
using namespace std;
inline int read()
{
    int  x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

queue<int> qu;
int cnt=1,n,m;
int head[2005],q[2005];
struct edge{
    int to,next,w;
}e[50005];

void ins(int f,int t,int w){e[++cnt].next=head[f];head[f]=cnt;e[cnt].to=t;e[cnt].w=w;}
void insw(int f,int t,int w){ins(f,t,w);ins(t,f,0);}

int dfs(int x,int f)
{
    if(x==T)return f;
    int used=0;
    for(int i=head[x];i;i=e[i].next)
    if(e[i].w&&q[e[i].to]==q[x]+1)
    {
        int w=dfs(e[i].to,min(e[i].w,f-used));
        used+=w;e[i].w-=w;e[i^1].w+=w;
        if(f==used)return f;
    }
    return used;
}

bool bfs(int lim)
{
    memset(q,0,sizeof(q));q[S]=1;qu.push(S);
    while(!qu.empty())
    {
        int x=qu.front();qu.pop();
        for(int i=head[x];i;i=e[i].next) if(e[i].w&&!q[e[i].to]&&(e[i].to-n<=lim||e[i].to==T))
        {q[e[i].to]=q[x]+1;qu.push(e[i].to);}    
    }
    return q[T]>0;
}

bool check(int x)
{
    int ans=0;
    for(int i=2;i<=cnt;i+=2) e[i].w=1,e[i^1].w=0;
    while(bfs(x))ans+=dfs(S,1000000);
    return ans==x;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)insw(S,i,1);
    for(int i=1;i<=m;i++)insw(read()+1,i+n,1),insw(read()+1,i+n,1),insw(i+n,T,1);
    int l=1,r=n,mid,ans=0;
    while(l<=r)
    {
        mid=(l+r)>>1;if(check(mid))ans=mid,l=mid+1;
        else r=mid-1;    
    }
    cout<<ans;
    return 0;
}

 

posted @ 2017-03-14 16:22  FallDream  阅读(329)  评论(0编辑  收藏  举报