题目大意:有F种食物,D种饮料
N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份)
一种食物被一头牛吃了之后,其余牛就不能吃了
第一行有N,F,D三个整数
接着2-N+1行代表第i头牛,前面两个整数是Fi与Di(食物与饮料的种类数量),接着是食物的种类与饮料的种类
N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份)
一种食物被一头牛吃了之后,其余牛就不能吃了
第一行有N,F,D三个整数
接着2-N+1行代表第i头牛,前面两个整数是Fi与Di(食物与饮料的种类数量),接着是食物的种类与饮料的种类
要求输出最多分配能够满足的牛的数量
思路分析:
这里想到的首先是dp,差点就给搞各种dp的队友了,后来想了想,状态比较复杂,用方程来推的话三四个方程也不够用。所以还是想了网络流的方法,现在呢,除了牛到食物和饮料有了权值,饮料食物自身也有了限制,这时如果我们把饮料当成两个点,两个点之间加入一条和它最大量相同的边,显然这两个点就能实现饮料(食物)的权值确定。
剩下的就是简单的网络流了。
附AC代码如下
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long
#define s(a) scanf("%d",&a)
#define scanf scanf_s
const int inf = 0x3f3f3f;
using namespace std;
const int N = 405;
/*
0=S
1-100=Cow
101-200=Food
201-300=Drink
301=E
*/
int n, m;
int Map[N][N], path[N], flow[N];
int start, endd;
queue<int>q;
int bfs() {
while (!q.empty()) q.pop();
memset(path, -1, sizeof(path));
path[start] = 0, flow[start] = inf;
q.push(start);
while (!q.empty()) {
int t = q.front();
q.pop();
if (t == endd) { break; }
for (int i = 1; i <= 401; i++) {
if (i != start && path[i] == -1 && Map[t][i]) {
flow[i] = flow[t]<Map[t][i] ? flow[t] : Map[t][i];
q.push(i);
path[i] = t;
}
}
}
if (path[endd] == -1) return -1;
return flow[endd];
}
int Edmonds_Karp() {
int max_flow = 0, step, now, pre;
while ((step = bfs()) != -1) {
max_flow += step;
now = endd;
while (now != start) {
pre = path[now];
Map[pre][now] -= step;
Map[now][pre] += step;
now = pre;
}
}
return max_flow;
}
void srcBuild(int food) {//num of food
for (int i = 1; i <= food; i++) {
Map[0][i] = 1;
}
}
void desBuild(int drink) {//num if drink
for (int i = 301; i <= drink + 300; i++) {
Map[i][401] = 1;
}
}
int main() {
ios::sync_with_stdio(false);
int n, f, d;
cin >> n >> f >> d;
srcBuild(f);
desBuild(d);
int x;
for (int i = 101; i <= 200; i++) {
Map[i][i + 100] = 1;
}
for (int i = 1; i <= n; i++) {
cin >> f >> d;
while (f--) {
cin >> x;
Map[x][i + 100] = 1;
}
while (d--) {
cin >> x;
Map[i + 200][300 + x] = 1;
}
}
start = 0;
endd = 401;
cout << Edmonds_Karp();
return 0;
}