bzoj1305: [CQOI2009]dance跳舞

网络流拆点建模。

注意二分查找的边界

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 500 + 10;
const int maxm = 40000 + 10;
const int INF = 0x3f3f3f3f;

int g[maxn],v[maxm],next[maxm],f[maxm],eid;
int S,T,vid;
int id[maxn][2][2];
char m[60][60];
int n,k;
int dist[maxn],gap[maxn];

void addedge(int a,int b,int c) {
    v[eid]=b; f[eid]=c; next[eid]=g[a]; g[a]=eid++;
    v[eid]=a; f[eid]=0; next[eid]=g[b]; g[b]=eid++;
}

void build(int x) {
    memset(g,-1,sizeof(g)); eid=0;
    for(int i=1;i<=n;i++) {
        addedge(S,id[i][0][0],x);
        addedge(id[i][0][0],id[i][0][1],k);
        addedge(id[i][1][1],id[i][1][0],k);
        addedge(id[i][1][0],T,x);    
    }
    
    for(int i=1;i<=n;i++) 
    for(int j=1;j<=n;j++) {
        if(m[i][j]=='Y') addedge(id[i][0][0],id[j][1][0],1);
        else addedge(id[i][0][1],id[j][1][1],1);
    }
}

int ISAP(int u,int flow) {
    if(u==T) return flow;
    
    int aug,cur=0,mindist=vid;
    for(int i=g[u];~i;i=next[i]) 
        if(f[i]&& dist[v[i]]+1==dist[u]) {
            aug=ISAP(v[i],min(flow-cur,f[i]));
            f[i]-=aug;
            f[i^1]+=aug;
            cur+=aug;
            if(cur==flow || dist[S]>=vid) {
                return cur;
            }
        }

    if(cur==0) {
        if(!--gap[dist[u]]) {
            dist[S]=vid;
            return cur;
        }
        for(int i=g[u];~i;i=next[i]) if(f[i])
            mindist=min(mindist,dist[v[i]]);
        ++gap[dist[u]=mindist+1];
    }
    
    return cur;
}

int max_flow() {
    memset(gap,0,sizeof(gap));
    memset(dist,0,sizeof(dist));
    gap[0]=vid;
    
    int res=0;
    while(dist[S]<vid) res+=ISAP(S,INF);
    return res;
}


bool check(int x) {
    build(x);
    return (max_flow()==x*n);
}

int main() {
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) {
        scanf("%s",m[i]+1);
        for(int x=0;x<=1;x++)
        for(int y=0;y<=1;y++)
            id[i][x][y]=++vid;    
    }
    S=++vid; T=++vid;
    
    int l=0,r=n,mid;
    while(l+1<r) {
        mid=(l+r)>>1;
        if(check(mid)) l=mid;
        else r=mid-1;            
    }
    printf("%d\n",check(r)?r:l);
    return 0;
}
posted @ 2016-05-16 10:53  invoid  阅读(139)  评论(0编辑  收藏  举报