(网络流)[ZJOI2009]假期的宿舍

https://www.luogu.org/problemnew/show/P2055
学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题。比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识。我们假设每个人只能睡和自己直接认识的人的床。那么一个解决方案就是 B 睡 A 的床而 C 睡 B 的床。而实际情况可能非常复杂,有的人可能认识好多在校学生,在校学生之间也不一定都互相认识。我们已知一共有 n 个人,并且知道其中每个人是不是本校学生,也知道每个本校学生是否回家。问是否存在一个方案使得所有不回家的本校学生和来看他们的其他人都有地方住。

n<=50, t<=20. 建图为人和床位分开,校外的人建一条由源点容量为1的边,校内的人分两种,如果不离校,源点连一条容量为1的边和建立一条自己到自己床位的边;如果离校则建立一条到汇点的容量为1的边。如果i和j有关系,因为每个人只能睡和自己有直接关系的人的床位,所以建一条由i人到j的床位的容量为1的边。跑出最大流判断需要呆在学校的人和流量相等是否即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pi;
const int maxn = 50 * 50 + 10;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
};
struct EdmondKarp
{
    int n, m;
    vector<Edge> edges;
    vector<int> G[maxn];
    int a[maxn], p[maxn];

    void init(int n)
    {
        for (register int i = 0; i < n; i++)
            G[i].clear();
        edges.clear();
    }
    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }
    int Maxflow(int s, int t)
    {
        int flow = 0;
        for (;;)
        {
            memset(a, 0, sizeof(a));
            queue<int> Q;
            Q.push(s);
            a[s] = INF;
            while (!Q.empty())
            {
                int x = Q.front();
                Q.pop();
                for (register int i = 0; i < G[x].size(); i++)
                {
                    Edge &e = edges[G[x][i]];
                    if (!a[e.to] && e.cap > e.flow)
                    {
                        p[e.to] = G[x][i];
                        a[e.to] = min(a[x], e.cap - e.flow);
                        Q.push(e.to);
                    }
                }
                if (a[t])
                    break;
            }
            if (!a[t])
                break;
            for (int u = t; u != s; u = edges[p[u]].from)
            {
                edges[p[u]].flow += a[t];
                edges[p[u] ^ 1].flow -= a[t];
            }
            flow += a[t];
        }
        return flow;
    }
};
int t, n, x, vis[maxn];
int main()
{
    register int i, j;
    scanf("%d", &t);
    while(t--) {
        EdmondKarp ek;
        memset(vis, 0, sizeof(vis));
        int cnt = 0;
        scanf("%d", &n);
        ek.init(2 * n + 2);
        for (i = 1; i <= n; i++) {
            scanf("%d", &x);
            if(x == 0) ek.AddEdge(0, i, 1), cnt++;
            else {
                ek.AddEdge(n + i, 2 * n + 1, 1);
                vis[i] = 1;
            }
        }
        for (i = 1; i <= n; i++) {
            scanf("%d", &x);
            if(vis[i]) {
                if(x == 0) {
                    ek.AddEdge(0, i, 1);
                    ek.AddEdge(i, i + n, 1);
                    cnt++;
                }
            }
        }
        for (i = 1; i <= n; i++) {
            for (j = 1; j <= n; j++) {
                scanf("%d", &x);
                if(!x) continue;
                ek.AddEdge(i, j + n, 1);
            }
        }
        printf("%s\n", ek.Maxflow(0, 2 * n + 1) == cnt ? "^_^" : "T_T");
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_40588429/article/details/84074510