bzoj1433: [ZJOI2009]假期的宿舍

二分图匹配。

每个点分为俩个点0和1,表示有床的人和要睡觉的人。跑最大流。

图中所有边的流量均为1

1.S向每个有床的人(0)连一条边。

2.每个不回家的人和校外的人(1)向T连一条边。

3.每个有床的人和自己连一条边(0->1)。

4.每个认识的人连一条边(0->1).

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 10000 + 10;
const int maxm = 20000 + 10;
const int inf = 0x3f3f3f3f;

int g[maxn],v[maxm],next[maxm],f[maxm],eid;
int id[maxn][2];
int n,S,T,cnt,vid;
int a[maxn],b[maxn];
int dist[maxn],gap[maxn];

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

void build() {
    memset(g,-1,sizeof(g)); eid=0; cnt=0; vid=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        id[i][0]=++vid;
        id[i][1]=++vid;
    }
    S=++vid; T=++vid;
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        if(a[i]) addedge(S,id[i][0],1);
    }
    
    for(int i=1;i<=n;i++) {
        scanf("%d",&b[i]);
        if(!a[i] || !b[i]) {
            cnt++;
            addedge(id[i][1],T,1);
        }
    }
    
    for(int i=1,t;i<=n;i++) 
        for(int j=1;j<=n;j++) {
            scanf("%d",&t);
            if(a[i] && t) addedge(id[i][0],id[j][1],1);
            if(a[i] || i==j) addedge(id[i][0],id[i][1],1);
        }                        
}

int ISAP(int u,int flow) {
    if(u==T) return flow;
    int cur=0,aug,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;
}

void solve() {
    int res=0;
    memset(dist,0,sizeof(dist));
    gap[0]=vid;
    while(dist[S]<vid) res+=ISAP(S,inf);
    printf(res==cnt?"^_^\n":"T_T\n");
}

int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        build();
        solve();    
    }
    return 0;    
}
posted @ 2016-06-16 13:50  invoid  阅读(48)  评论(0编辑  收藏