欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

洛谷P1402 酒店之王 网络流

程序员文章站 2022-05-15 14:08:24
...

做一下往年省夏的题)
网络流比较显然,拆点要注意一下
一开始把超级源点S的出边容量设成inf -> wa 60分
改成1 -> wa 70分 才发现建图有问题
洛谷P1402 酒店之王 网络流
这样是能过样例 还能水70分 但是不合题意, 2号点也能蹭到1号点喜欢的菜了……
所以正确建图应该是源点连房间 然后房间连人 人->人拆出来的出点->菜 ->汇点 这样能保证一人一菜一房间

#include<cstdio>
#include<cstring>
#include<algorithm>
#define Max(_A,_B) (_A>_B?_A:_B)
#define Min(_A,_B) (_A<_B?_A:_B)
#define inf 0x3f3f3f3f
int read(){
    int s = 0;bool f = 1;char c = getchar();
    while(c > '9' || c < '0'){if(c == '-') f = 0; c = getchar();}
    while(c >= '0' && c <= '9') {
        s = s * 10 + c - '0';
        c = getchar();
        }
    return f == 1 ? s : -s;  
}
const int maxn = 1007, maxm = 2000001;
int n, p, q;
struct edge{
    int v, c, nxt;
}e[maxm << 1];
int head[maxn], eid = 0, d[maxn], Q[maxn], qh, qt, S, T;
void init() {
    memset(head, -1, sizeof(head));
    eid = 0;
}
void insert(int u, int v, int c) {
    e[eid].v = v; e[eid].c = c; e[eid].nxt = head[u]; head[u] = eid++;
    e[eid].v = u; e[eid].c = 0; e[eid].nxt = head[v]; head[v] = eid++;
}
bool bfs() {
    qh = qt = 0;
    memset(d, -1, sizeof(d));
    d[S] = 0;
    Q[qt++] = S;
    while(qh != qt) {
        int u = Q[qh++]; if(qh == maxn) qh = 0;
        for (int i = head[u]; ~i; i = e[i].nxt) {
            int v = e[i].v;
            if(e[i].c > 0 && d[v] == -1) {
                d[v] = d[u] + 1;
                Q[qt++] = v;
                if(qt == maxn) qt = 0;
            }
        }
    }
    return d[T] != -1;
}
int dfs(int u, int flow) {
    if(u == T) return flow;
    int res = 0, tmp;
    for (int i = head[u]; ~i; i = e[i].nxt) {
        int v = e[i].v;
        if(e[i].c > 0 && d[v] == d[u] + 1) {
            tmp = dfs(v,Min(flow, e[i].c));
            res += tmp;
            flow -= tmp;
            e[i].c -= tmp;
            e[i ^ 1].c += tmp;
            if(flow == 0) break;
        }
    }
    if(res == 0) d[u] = -1;
    return res;
}
int dinic(){
    int res = 0;
    while(bfs()) res += dfs(S, inf);
    return res;
}
/*
编号:点:1~2n 其中后面的n+1~2n为拆出来的中间点
p间房间:2n + 1 ~ 2n + p
q道菜: 2n + p + 1 ~ 2n + p + q
*/
int maxp, maxq;
int main() {
    n = read(), p = read(), q = read();
    init();
    S = 0, T = maxn - 1;
    maxp = 2 * n + p;
    maxq = 2 * n + p + q;
    for (int i = 2 * n + 1; i <= maxp; i++) insert(S, i, 1);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= p; j++) {
            if(read()) {
                insert(2 * n + j, i, 1);
            }
        }
        insert(i, i + n, 1);
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= q; j++) {
            if(read()) {
                insert(i + n, j + maxp, 1);
            }
        }
    }
    for (int i = maxp + 1; i <= maxp + q; i++) insert(i, T, 1);
    printf ("%d\n", dinic());
    return 0;
}