嘘~ 正在从服务器偷取页面 . . .

洛谷P1402 酒店之王 题解


洛谷P1402 酒店之王 题解

题目链接:P1402 酒店之王

题意

小红花酒店的老板 cxy 想成为酒店之王,本着这种希望,第一步要将酒店变得人性化。由于很多来住店的旅客有自己喜好的房间色调、阳光等,也有自己所爱的菜,但是该酒店只有 $p$ 间房间,一天只有固定的 $q$ 道不同的菜,每个房间只能住一位客人,每道菜也只能给一位客人食用。

有一天来了 $n$ 个客人,每个客人说出了自己喜欢哪些房间,喜欢哪道菜。但是很不幸,可能做不到让所有顾客满意(满意的条件是住进喜欢的房间且吃到喜欢的菜)。

要怎么分配,能使最多顾客满意呢?

输入格式

第一行给出三个整数,分别表示表示 $n,p,q$。

之后 $n$ 行,每行 $p$ 个整数,只可能是 $0$ 或 $1$,第 $i$ 行第 $j$ 个数表示第 $i$ 个人喜不喜欢第 $j$ 个房间($1$ 表示喜欢, $0$ 表示不喜欢)。

之后 $n$ 行,每行 $q$ 个整数,只可能是 $0$ 或 $1$,第 $i$ 行第 $j$ 个数表示第 $i$ 个人喜不喜欢第 $j$ 道菜($1$ 表示喜欢, $0$ 表示不喜欢)。

输出格式

最大的顾客满意数。

数据范围

对于全部的测试点,保证 $1 \leq n,p,q \leq 100$。

网络流经典题。

我们可以将所有人和所有菜连边,这构成了一个二分图。

然后我们再将所有人和所有房间连边,这构成了一个“镜像的二分图”

但是因为一个人只能匹配一个酒店&一道菜,这意味着需要把人拆点。

具体地,点 $A$ 拆成 点 $A$ 和 $A’$ ,有边 $A \to A’$ 流量为 $1$ (以及反向边流量为 $0$ )

然后只要把左侧的酒店和源点 $s$ 连一下,右侧的菜和 $t$ 连一下,跑个最大流就好了。

时间复杂度 $\mathcal{O}(|V|^2|E|)$ ,采用了 $\mathtt{Dinic}$ (其实是怕记错 ISAP 然后调半天

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(155))
#define M ((int)(1e6 + 255))

// A : [1,n], B : [n+1,n+p];
// C : [n+p+1, n+p+q], A' : [n+p+q+1, n+p+q+n];
int n,p,q,s,t,tot,pos=1,head[N * 4],dep[N * 4],now[N * 4];
struct Edge { int u,v,w,next; } e[M * 4];
void addEdge(int u,int v,int w)
{ e[++pos] = {u,v,w,head[u]}; head[u] = pos; }
void add(int u,int v) { addEdge(u,v,1); addEdge(v,u,0); }
queue<int> que;
bool bfs()
{
    for(int i=1; i<=tot; i++) dep[i] = INF;
    que.push(s); dep[s] = 0; now[s] = head[s];
    while(!que.empty())
    {
        int u = que.front(); que.pop();
        for(int i=head[u]; i; i=e[i].next)
        {
            int v = e[i].v;
            if(e[i].w > 0 && dep[v] == INF)
            {
                dep[v] = dep[u] + 1;
                now[v] = head[v]; que.push(v);
            }
        }
    }
    return dep[t] != INF;
}
int dfs(int u,int in)
{
    if(u == t) return in;
    int out = 0;
    for(int i=now[u]; i; i=e[i].next)
    {
        if(!in) break; int v = e[i].v; now[u] = i;
        if(e[i].w > 0 && dep[v] == dep[u] + 1)
        {
            int res = dfs(v, min(in, e[i].w));
            e[i].w -= res; e[i ^ 1].w += res;
            in -= res; out += res;
        }
    }
    if(!out) dep[u] = INF;
    return out;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> p >> q; tot = n + p + q + n; s = ++tot; t = ++tot;
    for(int i=1; i<=n; i++)
        for(int j=1,x; j<=p; j++) { cin >> x; if(x) add(j+n, i); }
    for(int i=1; i<=n; i++)
        for(int j=1,x; j<=q; j++) { cin >> x; if(x) add(i+p+q+n, j+n+p); }
    
    for(int i=1; i<=p; i++) add(s, i+n);
    for(int i=1; i<=q; i++) add(i+n+p, t);
    for(int i=1; i<=n; i++) add(i, i+n+p+q);
    int maxflow = 0;
    while(bfs()) maxflow += dfs(s, INF);
    cout << maxflow << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录