洛谷P1402 酒店之王 网络流

做一下往年省夏的题)
网络流比较显然,拆点要注意一下
一开始把超级源点S的出边容量设成inf -> wa 60分
改成1 -> wa 70分 才发现建图有问题
这里写图片描述
这样是能过样例 还能水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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值