题目链接;
题意:
有n个顾客,有m个猪圈,每个猪圈有一定的猪,在开始的时候猪圈都是关闭的,顾客来买猪,顾客打开某个猪圈,可以在其中挑选一定的猪的数量,在这个顾客走后,可以在打开的猪圈中将某个猪圈的一些猪牵到另外一个打开的猪圈,然后所有的猪圈会关闭,这样下一个顾客来了继续上面的工作。
第一行是两个整数:m和n(1≤M≤1000,1≤N≤100)
m是猪圈的数目,n是顾客的数目
第二行是m个整数,为每个猪圈中初始猪的数目,范围是[0,1000]
第三行接下来有N行,每行第一个数A代表第几个顾客会依次打开A个猪圈,然后跟着有A个数,代表顾客打开的是哪个猪圈.最后有一个数代表这个顾客可以买多少只猪
现在求怎么一种方法,使所有顾客买的猪的总数最大.
思路:
源点 -》 顾客 -》 汇点 。(源点为0,顾客编号为1~n,汇点为n + 1)
第一步:
源点与顾客之间: 能够第一次进入i号猪圈的顾客与源点相连,流量为i号猪圈的猪数量。
第二步:
顾客与顾客之间:进入i号猪圈的第p位与第p + 1位连接,流量为无限大(因为与原点相连的那条流量做出了限制),随意支配猪的流动。
第三步:
顾客与汇点之间:每位顾客都可以与汇点相连,流量为该顾客需要的猪数量。
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#define MAXN 2000+50
#define INF 0x3f3f3f
using namespace std;
int dist[MAXN], cur[MAXN], head[MAXN];
int pig[MAXN], need[MAXN], vis[MAXN];
int top;
vector<int> G[MAXN];
struct Edge {
int to, cap, flow, next;
}edge[MAXN * 200];
void addedge(int a, int b, int c) {
// int i; //处理重边,可以不用
// for(i = head[a]; i != -1; i = edge[i].next) {
// if(edge[i].to == b) break;
// }
// if(i != -1) {
// if(c != INF) edge[i].cap += c;
// return;
// }
Edge E1 = {b, c, 0, head[a]};
edge[top] = E1;
head[a] = top++;
Edge E2 = {a, 0, 0, head[b]};
edge[top] = E2;
head[b] = top++;
}
bool BFS(int start, int end) {
memset(dist, -1, sizeof(dist));
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(start);
vis[start] = 1;
dist[start] = 0;
while(!Q.empty()) {
int u = Q.front();
Q.pop();
for(int i = head[u]; i != -1; i = edge[i].next) {
Edge E = edge[i];
if(!vis[E.to] && E.cap > E.flow) {
dist[E.to] = dist[u] + 1;
vis[E.to] = 1;
if(E.to == end) return true;
Q.push(E.to);
}
}
}
return false;
}
int DFS(int x, int cost, int end) {
if(x == end || cost == 0) return cost;
int flow = 0, f;
for(int& i = cur[x]; i != -1; i = edge[i].next) {
Edge& E = edge[i];
if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(cost, E.cap - E.flow), end)) > 0) {
E.flow += f;
edge[i ^ 1].flow -= f;
flow += f;
cost -= f;
if(cost == 0) break;
}
}
return flow;
}
int Maxflow(int start, int end) {
int flow = 0;
while(BFS(start, end)) {
memcpy(cur, head, sizeof(head));
flow += DFS(start, INF, end);
}
return flow;
}
int t, k, n, m;
void getmap() { //核心部分
for(int i = 1; i <= m; i++) {
scanf("%d", &pig[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%d", &t);
while(t--) {
scanf("%d", &k);
G[k].push_back(i); //猪圈和顾客相连接
}
scanf("%d", &need[i]); //顾客需要的猪
}
for(int i = 1; i <= m; i++) {
int u = G[i][0]; //和源点链接
addedge(0, u, pig[i]);
for(int j = 0; j < G[i].size() - 1; j++) { //别忘了减一
int x = G[i][j];
int y = G[i][j + 1];
addedge(x, y, INF); //前后来到i号猪圈的顾客之间流无限大
}
}
for(int i = 1; i <= n; i++) {
addedge(i, n + 1, need[i]);
}
}
int main() {
while(scanf("%d %d", &m, &n) != EOF) {
top = 0;
memset(head, -1, sizeof(head));
memset(edge, 0, sizeof(edge));
memset(G, 0, sizeof(G));
getmap();
printf("%d\n", Maxflow(0, n + 1));
}
return 0;
}