mmp这个题又调了好久, 网络流板子
dis[S]
d
i
s
[
S
]
竟然没设为
1
1
一开始想的做法是如果有人喜欢房间
j
j
菜的话, 就,
j
j
连边, 但是这是一个很显然的错的, 因为当有两个人喜欢相同的搭配的时候, 那搭配可以同时让多人满意 就会算重。
那么考虑解决算重这个问题, 我们把一个人放在他夏欢的菜和房间之间不就可以了吗?实际上还是错误的, 这样只能保证两个不同的人喜欢相同搭配的时候, 相同的搭配只会算在一个人身上, 不能保证一个人不会被多种搭配算, 那么我们再对每个人进行一次限制, 我们把每个人拆成两个, 一个连向房间, 另一个连向菜, 那么我们就成功限制了一个人只能选择一种搭配, 问题就解决了。
最后建图从向每一道菜连边, 从每一道菜向每个喜欢它的人连的边, 每个人分裂出一个自己再向自己连边, 分裂出的自己向每个房间连边, 最后每个房间向
T
T
<script type="math/tex" id="MathJax-Element-8">T</script>连边, 在这个建立好的模型上直接跑网络最大流就好了
链接
#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
#define inf (0x3f3f3f3f)
using namespace std;
const int maxn = 1000 + 10, maxm = 4e6 + 1e3;
int n, p, q, s, t;
namespace Maxflow {
int to[maxm << 1], head[maxn], nxt[maxm << 1], w[maxm << 1], e = 1;
int dis[maxn];
void add(int x, int y, int z) {
to[++ e] = y;
nxt[e] = head[x];
head[x] = e;
w[e] = z;
if(z) add(y, x, 0);
}
bool bfs() {
queue<int> q;
memset(dis, 0, sizeof(dis));
dis[s] = 1, q.push(s);
while(!q.empty()) {
int k = q.front(); q.pop();
go(k, i)
if(w[i] && !dis[to[i]]) {
dis[to[i]] = dis[k] + 1;
q.push(to[i]);
}
}
return dis[t];
}
int dfs(int x, int flow) {
if(x == t || !flow)
return flow;
int used = 0;
go(x, i)
if(dis[to[i]] == dis[x] + 1) {
int di = dfs(to[i], min(flow, w[i]));
w[i] -= di, w[i ^ 1] += di;
flow -= di, used += di;
if(!flow) break;
}
return used;
}
int dinic() {
int res = 0;
while(bfs())
res += dfs(s, inf);
return res;
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("1402.in", "r", stdin);
freopen("1402.out", "w", stdout);
#endif
int k; scanf("%d%d%d", &n, &p, &q);
s = p + q + (n << 1) + 1, t = s + 1;
For(i, 1, n)
For(j, 1, p) {
scanf("%d", &k);
if(k) Maxflow::add(j, i + p, 1);
}
For(i, 1, n)
For(j, 1, q) {
scanf("%d", &k);
if(k) Maxflow::add(i + n + p, j + (n << 1) + p, 1);
}
For(i, 1, n) Maxflow::add(i + p, i + n + p, 1);
For(i, 1, p) Maxflow::add(s, i, 1);
For(i, 1, q) Maxflow::add(i + p + (n << 1), t, 1);
printf("%d\n", Maxflow::dinic());
return 0;
}