[BZOJ] 1191: [HNOI2006]超级英雄Hero

一看:裸二分图最大匹配/最大流么,码码码

交,WA..

仔细读题,是这样的,一旦有一个题答不出游戏就结束了,看起来需要动态加边的最大流?

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define Ri(x) ((x)+m)
using namespace std;

inline int rd() {
    int ret=0,f=1;
    char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=2048;
const int INF=1<<29;

struct Edge {
    int next,to,w;
} e[MAXN<<2];
int ecnt=1,head[MAXN];
inline void add(int x,int y,int w) {
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    e[ecnt].w = w;
    head[x] = ecnt;
}

int n,m;
int S,T;
bool visr[MAXN];

int dep[MAXN];
queue<int> Q;
bool bfs() {
    memset(dep,0,sizeof(dep));
    Q.push(S);
    dep[S]=1;
    while(!Q.empty()) {
        int top=Q.front();
        Q.pop();
        for(int i=head[top]; i; i=e[i].next) {
            int v=e[i].to;
            if(!e[i].w||dep[v]) continue;
            dep[v]=dep[top]+1;
            Q.push(v);
        }
    }
    return dep[T];
}

int cur[MAXN];
int dfs(int x,int flow) {
    if(x==T) return flow;
    int used=0,tmp;
    for(int i=cur[x]; i; i=e[i].next) {
        int v=e[i].to;
        if(dep[v]!=dep[x]+1) continue;
        tmp=dfs(v,min(e[i].w,flow-used));
        e[i].w-=tmp;
        e[i^1].w+=tmp;
        used+=tmp;
        if(e[i].w) cur[x]=i;
        if(used==flow) return flow;
    }
    if(!used) dep[x]=0;
    return used;
}

int mxflow;
void dinic() {
    while(bfs()) {
        memcpy(cur,head,sizeof(head));
        mxflow+=dfs(S,INF);
    }
}

bool vis[MAXN];

int main() {
    n=rd();
    m=rd();
    S=n+m+1;
    T=n+m+2;
    int x,y;

    for(int i=1; i<=m; i++) {
        add(S,i,1),add(i,S,0);
        x=rd();y=rd();x++;y++;
        add(i,Ri(x),1);add(Ri(x),i,0);
        if(!vis[x]) add(Ri(x),T,1),add(T,Ri(x),0);
        vis[x]=1;
        if(x!=y) {
            add(i,Ri(y),1);add(Ri(y),i,0);
            if(!vis[y]) add(Ri(y),T,1),add(T,Ri(y),0);
            vis[y]=1;
        }
        dinic();
        if(mxflow<i) return cout<<mxflow,0;
    }
    cout<<mxflow;
    return 0;
}

但是有这样一个事情,如果能答x道,一定能答y (y<x)道(显然啊)

因此可以二分一下!dinic的优秀复杂度,不慢的

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define Ri(x) ((x)+m)
using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=2048;
const int INF=1<<29;

struct Edge{
    int next,to,w;
}e[MAXN<<2];
int ecnt=1,head[MAXN];
inline void add(int x,int y,int w){
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    e[ecnt].w = w;
    head[x] = ecnt;
}

int n,m;
int S,T;

int dep[MAXN];
queue<int> Q;
bool bfs(){
    memset(dep,0,sizeof(dep));
    Q.push(S);dep[S]=1;
    while(!Q.empty()){
        int top=Q.front();Q.pop();
        for(int i=head[top];i;i=e[i].next){
            int v=e[i].to;
            if(!e[i].w||dep[v]) continue;
            dep[v]=dep[top]+1;
            Q.push(v);
        }
    }
    return dep[T];
}

int cur[MAXN];
int dfs(int x,int flow){
    if(x==T) return flow;
    int used=0,tmp;
    for(int i=cur[x];i;i=e[i].next){
        int v=e[i].to;
        if(dep[v]!=dep[x]+1) continue;
        tmp=dfs(v,min(e[i].w,flow-used));
        e[i].w-=tmp;e[i^1].w+=tmp;
        used+=tmp;
        if(e[i].w) cur[x]=i;
        if(used==flow) return flow;
    }
    if(!used) dep[x]=0;
    return used;
}

int mxflow;
void dinic(){
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        mxflow+=dfs(S,INF);
    }
}

int savx[MAXN],savy[MAXN];

bool solve(int mid){
    ecnt=1;
    memset(head,0,sizeof(head));
    mxflow=0;
    int x,y;
    for(int i=1;i<=mid;i++){
        x=savx[i];y=savy[i];
        add(i,Ri(x),1);add(Ri(x),i,0);
        if(x==y) continue;
        add(i,Ri(y),1),add(Ri(y),i,0);
    }
    for(int i=1;i<=m;i++) add(S,i,1),add(i,S,0);
    for(int i=1;i<=n;i++){
        add(Ri(i),T,1);add(T,Ri(i),0);
    }
    dinic();
    return mxflow==mid;
}

int main(){
    n=rd();m=rd();
    S=n+m+1;T=n+m+2;
    int x,y;
    for(int i=1;i<=m;i++){
        savx[i]=rd()+1;savy[i]=rd()+1;
        add(i,Ri(x),1);add(Ri(x),i,0);
    }
    int l=0,r=m,mid,ans;
    while(l<=r){
        mid=(l+r)>>1;
        if(solve(mid)) l=mid+1,ans=mid;
        else r=mid-1;
    }
    cout<<ans;
    return 0;
}

本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9401741.html

原文地址:https://www.cnblogs.com/ghostcai/p/9401741.html