bzoj1433: [ZJOI2009]假期的宿舍

传送门
显然网络流呀。
源点向所有有床位的连边
需要床位的向汇点连边
如果i可以睡j的床,i向j‘连边
裸题呀。

#include<cstring>
#include<cmath>   
#include<cstdio>  
#include<iostream>  
#include<cstdlib>   
#include<algorithm>
#define inf 2100000000
#define N 105
using namespace std;
struct edge{
    int from,to,v,next;
}e[10005];
int tot,cas,n,sum;
int head[N],a[N],b[N],c[N][N],dis[N],q[N],from[N];
inline void add(int x,int y,int u){
    e[++tot].from=x;
    e[tot].to=y;
    e[tot].v=u;
    e[tot].next=head[x];
    head[x]=tot;
}
inline void ins(int x,int y,int u){
    add(x,y,u);
    add(y,x,0);
}
inline void build(){
    memset(head,0,sizeof(head));
    memset(from,0,sizeof(from));
    tot=1;
    sum=0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=n;j++)
            if ((a[i]==0||(a[i]==1&&b[i]==0))&&a[j]&&c[i][j]) ins(i,j+n,1);
    for (int i=1;i<=n;i++)
        if (a[i]==0||(a[i]==1&&b[i]==0)){
            sum++;
            ins(n*2+1,i,1);
        }
    for (int i=1;i<=n;i++) if (a[i]) ins(i+n,n*2+2,1);
}
inline int spfa(){
    for (int i=1;i<=n*2+2;i++) dis[i]=inf;
    int h=0,t=1,x;
    q[1]=n*2+1;
    dis[n*2+1]=0;
    while (h<t){
        x=q[++h];
        for (int i=head[x];i;i=e[i].next)
            if (dis[e[i].to]==inf&&e[i].v){
                dis[e[i].to]=dis[x]+1;
                from[e[i].to]=i;
                q[++t]=e[i].to;
            }
    }
    if (dis[n*2+2]==inf) return 0;
    return 1;
}
inline void del(){
    sum--;
    for (int i=from[n*2+2];i;i=from[e[i].from]){
        e[i].v--;
        e[i^1].v++;
    }
}
int main(){
    scanf("%d",&cas);
    while (cas--){
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]);
        for (int i=1;i<=n;i++) scanf("%d",&b[i]);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++) scanf("%d",&c[i][j]);
        for (int i=1;i<=n;i++) if (a[i]) c[i][i]=1;
        build();
        while (spfa()) del();
        if (!sum) printf("^_^\n"); else printf("T_T\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值