【BZOJ1433】【codevs2347】假期的宿舍,最大流

来源:互联网 发布:淘宝分类模块代码 编辑:程序博客网 时间:2024/05/16 14:23

传送门1
传送门2
写在前面:蛤蛤
思路:
(要拆点啊!naive的我一开始没拆点竟然还过了4个点)
每个人拆成两个点,一个在源点那里,一个在汇点那里
1.s连本校学生,容量为1的边(发床了)
2.没回家的本校学生和外面的人往t连容量为1的边(需要床睡觉)
3.认识的人(包括自己的点)之间连容量为1的边
跑出最大流,判断其是否与需要的床数相等即可
注意:拆点啊!拆点
代码:

#include<bits/stdc++.h>using namespace std;int n,tot,s,t,T;int first[125],dis[125];bool a[65];struct edge{    int v,w,next;}e[100000];void add(int x,int y,int z){e[++tot]=(edge){y,z,first[x]};first[x]=tot;}queue<int>q;bool bfs(){    memset(dis,0,sizeof(dis));    q.push(s);dis[s]=1;    while (!q.empty())    {        int k=q.front();        q.pop();        for (int i=first[k];i;i=e[i].next)            if(!dis[e[i].v]&&e[i].w)                q.push(e[i].v),dis[e[i].v]=dis[k]+1;    }    return dis[t];}int dfs(int x,int maxn){    if (x==t) return maxn;    int used=0;    for (int i=first[x];i;i=e[i].next)        if(dis[e[i].v]==dis[x]+1)        {            int k=dfs(e[i].v,min(maxn-used,e[i].w));            e[i].w-=k;e[i^1].w+=k;            used+=k;            if (used==maxn) return maxn;        }    if (!used) dis[x]=0;    return used;}main(){    int x;    scanf("%d",&T);    while (T--)    {        memset(first,0,sizeof(first));        scanf("%d",&n);        int ans=n;        t=2*n+1;tot=1;        for (int i=1;i<=n;i++)        {            scanf("%d",a+i);            if (a[i])                add(s,i,1),                add(i,s,0);            else add(i+n,t,1),add(t,i+n,0);        }        for (int i=1;i<=n;i++)        {            scanf("%d",&x);            if (a[i])                if (!x) add(i+n,t,1),add(t,i+n,0);                else ans--;        }        for (int i=1;i<=n;i++)            for (int j=1;j<=n;j++)            {                scanf("%d",&x);                if (x||i==j) add(i,j+n,1),add(j+n,i,0);            }        while (bfs()) ans-=dfs(s,0x7fffff);        if (ans) puts("T_T");        else puts("^_^");    }}
0 0