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

洛谷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 !
评论
  目录