P2055 [ZJOI2009]假期的宿舍

Posted garen-wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2055 [ZJOI2009]假期的宿舍相关的知识,希望对你有一定的参考价值。

有点烧脑。。。


这道题是求二分图完美匹配。没看请题意还不知道是求完美匹配,结果爆零。

人一共分三种:

  1. 在校学生 && 回家。这类人拥有一个床,但是不睡。

  2. 在校学生 && 不回家。这类人拥有一个床,但也要睡一个床。有时不一定睡自己的。

  3. 外来学生。这类人没床却想睡觉。

显然要用(2n)的空间来建立人和床。

等待匹配的人只有1、3两种情况,等待匹配的床只有1、2两种情况。

第1种情况连床没什么卵用。又不睡。

只有第2种情况的人可以连自己的床。

第3种情况的人一定要睡别人的床。

在2、3种情况中,只要认识的人有床,就可以连接

然后套个二分图匹配的样子,跑跑网络流就ok了。

最后判断答案是不是等于人数,输出那两个表情即可。

代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
const int maxn = 1005, INF = 19260817;
struct Edges
{
    int next, to, weight;
} e[1000005];
int head[maxn], tot;// remember to set tot = 1
int n, s, t;
bool in_school[maxn], go_home[maxn];
int dep[maxn], cur[maxn];
void link(int u, int v, int w)
{
    e[++tot] = (Edges){head[u], v, w};
    head[u] = tot;
}
void addEdges(int u, int v, int w)
{
    link(u, v, w); link(v, u, 0);
}
int read()
{
    int ans = 0; char ch = getchar();
    while(ch > ‘9‘ || ch < ‘0‘) ch = getchar();
    while(ch >= ‘0‘ && ch <= ‘9‘)
    {
        ans = ans * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return ans;
}
bool bfs()
{
    memset(dep, 0, sizeof(dep));
    std::queue<int> q;
    dep[s] = 1; q.push(s);
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = head[u]; i; i = e[i].next)
        {
            int v = e[i].to;
            if(!dep[v] && e[i].weight > 0)
            {
                dep[v] = dep[u] + 1;
                q.push(v);
            }
        }
    }
    return dep[t];
}
int dfs(int u, int flow)
{
    if(u == t) return flow;
    for(int &i = cur[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if(dep[v] == dep[u] + 1 && e[i].weight > 0)
        {
            int di = dfs(v, std::min(e[i].weight, flow));
            if(di > 0)
            {
                e[i].weight -= di;
                e[i ^ 1].weight += di;
                return di;
            }
        }
    }
    return 0;
}
int dinic()
{
    int ans = 0;
    while(bfs())
    {
        for(int i = 1; i <= t; i++) cur[i] = head[i];
        while(int temp = dfs(s, INF)) ans += temp;
    }
    return ans;
}
int main()
{
    int T = read();
    while(T--)
    {
        // how to define nodes?
        // [1, n] person
        // [n + 1, n + n] beds
        // not go home->need bed
        // only do in-school students have beds
        // not in-school students->the persons visiting
        // go home->never consider them
        tot = 1; memset(head, 0, sizeof(head)); memset(e, 0, sizeof(e));
        n = read();
        int cnt = 0;
        s = n + n + 1; t = s + 1;
        for(int i = 1; i <= n; i++) in_school[i] = read();
        for(int i = 1; i <= n; i++) go_home[i] = read();
        for(int i = 1; i <= n; i++)
        {
            addEdges(s, i, 1);
            addEdges(n + i, t, 1);
            if((in_school[i] && !go_home[i]) || !in_school[i]) cnt++;
        }
        for(int i = 1; i <= n; i++)
        {
            if(in_school[i] && !go_home[i]) addEdges(i, n + i, 1);
            for(int j = 1; j <= n; j++)
            {
                int temp = read();
                if(temp && in_school[j] && !(in_school[i] && go_home[i])) addEdges(i, n + j, 1);
            }
        }
        int ans = dinic();
        if(ans == cnt) printf("^_^
");
        else printf("T_T
");
    }
    return 0;
}

以上是关于P2055 [ZJOI2009]假期的宿舍的主要内容,如果未能解决你的问题,请参考以下文章

P2055 [ZJOI2009]假期的宿舍

P2055 [ZJOI2009]假期的宿舍(二分图&最大流)

P2055 [ZJOI2009]假期的宿舍

P2055 [ZJOI2009]假期的宿舍

P2055 [ZJOI2009]假期的宿舍 - 二分图最大匹配

bzoj 1433: [ZJOI2009]假期的宿舍