ZJOI2009 假期的宿舍

传送门

这还是很显然是一道二分图匹配的题……(看数据范围辣么小)

其实这题就是建图稍微复杂一点。对于每个学生,我们把他们的床连到汇点上,然后对于每个没回家的和外来的人,我们把他们连到源点上,之后在人和床之间就按给定的关系连上就可以。注意自己和自己的床要连一条边。

处理过程比较繁琐……我们可以选择用1~n表示人,n+1~2*n表示床,其中n+i表示第i个人的床。这样的话即使有一些人不在校,我们也可以连边,反正他们和源汇点也不联通,计算的时候没什么关系。

之后直接跑dinic即可。(仍然不会匈牙利)

上代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
const int M = 505;
const int N = 100005;
const int INF = 1e9;
typedef long long ll;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
    }
    return ans * op;
}

struct node
{
    int from,next,to,v;
}e[N];
int t,n,deep[M],g[55][55],bcnt,scnt,ecnt = -1,head[M],cur[M],maxflow,source,sink;
bool stu[M],out[M];
queue <int> q;

void add(int x,int y,int z)
{
    e[++ecnt].from = x;
    e[ecnt].to = y;
    e[ecnt].v = z;
    e[ecnt].next = head[x];
    head[x] = ecnt;
}

void clear()
{
    memset(stu,0,sizeof(stu));
    memset(out,0,sizeof(out));
    memset(head,-1,sizeof(head));
    memset(cur,-1,sizeof(cur));
    ecnt = -1,bcnt = scnt = maxflow = 0;
    memset(e,0,sizeof(e));
    source = 0,sink = 105;
}

void build()
{
    n = read();
    rep(i,1,n) 
    {
        stu[i] = read();
        if(stu[i]) add(i+n,sink,1),add(sink,i+n,0);
    }
    rep(i,1,n)
    {
        out[i] = read();
        if(stu[i] && !out[i]) add(source,i,1),add(i,source,0),scnt++;
        if(!stu[i]) add(source,i,1),add(i,source,0),scnt++;
    }
    rep(i,1,n)
        rep(j,1,n) 
        {
            g[i][j] = read();
            if(i == j && stu[i] && !out[i]) add(i,i+n,1),add(i+n,i,0);
            if(g[i][j]) add(i,j+n,1),add(j+n,i,0);  
        }
}

bool bfs(int s,int t)
{
    memset(deep,-1,sizeof(deep));
    while(!q.empty()) q.pop();
    rep(i,0,sink+1) cur[i] = head[i];
    deep[s] = 0,q.push(s);
    while(!q.empty())
    {
        int k = q.front();q.pop();
        for(int i = head[k];i != -1;i = e[i].next)
        {
            if(deep[e[i].to] == -1 && e[i].v)
            deep[e[i].to] = deep[k] + 1,q.push(e[i].to);
        }
    }
    if(deep[t] == -1) return 0;
    else return 1;
}

int dfs(int s,int t,int limit)
{
    if(!limit || s == t) return limit;
    int flow = 0;
    for(int i = cur[s];i != -1;i = e[i].next)
    {
        cur[s] = i;
        if(deep[e[i].to] != deep[s] + 1) continue;
        int f = dfs(e[i].to,t,min(limit,e[i].v));
        if(f)
        {
            e[i].v -= f,e[i^1].v += f ;
            flow += f,limit -= f;
            if(!limit) break;
        }
    }
    if(!flow) deep[s] = -233333;
    return flow;
}

void dinic(int s,int t)
{
    while(bfs(s,t)) maxflow += dfs(s,t,INF);
}

int main()
{
    t = read();
    while(t--)
    {
        clear();
        build();
        dinic(source,sink);
        if(maxflow == scnt) printf("^_^\n");
        else printf("T_T\n");
    }
    return 0;
}

 

posted @ 2018-08-30 22:59  CaptainLi  阅读(166)  评论(0编辑  收藏  举报