题目链接

建图+ford最大流

建图: 如果把猪圈看作节点建图,就需要考虑顾客买猪的顺序,如果以顾客为节点则不需要。 从第一个顾客开始,从源点向顾客i连一条边,容量为没被访问过且顾客能开的猪圈猪数量的总和,如果有猪圈被顾客j访问过,那么 从j向i连一条边(有向), 容量为INF,最后让i向汇点连一条边,容量为顾客要买猪的数量。

下面用的是ford算法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int Maxn = 100+10;
const int INF = 0x3f3f3f3f;

struct Edge {
	int v, cap, flow, next;
} edge[Maxn*Maxn];

int h[Maxn], edge_cnt, num[Maxn*10], a[Maxn*10], tmp[Maxn*10];
bool vis[Maxn];

void add (int u, int v, int c) {
	edge[edge_cnt].v = v;
	edge[edge_cnt].cap = c;
	edge[edge_cnt].flow = 0;
	edge[edge_cnt].next = h[u];
	h[u] = edge_cnt++;

	edge[edge_cnt].v = u;
	edge[edge_cnt].cap = 0;
	edge[edge_cnt].flow = 0;
	edge[edge_cnt].next = h[v];
	h[v] = edge_cnt++;
}

int dfs(int cur, int t, int f) {
	if(cur == t) return f;
	for(int i = h[cur]; i != -1; i = edge[i].next) {
		Edge &e = edge[i];
		if(!vis[e.v] && e.cap > e.flow) {
			vis[e.v] = true;
			int flow = dfs(e.v, t, min(f, e.cap-e.flow));
			if(flow > 0) {
				e.flow += flow;
				edge[i^1].flow -= flow;
				return flow;
			}
		}
	}
	return 0;
}

void ford(int s, int t) {
	int ans = 0;
	while(1) {
		memset(vis, false, sizeof(vis));
		vis[s] = true;
		int flow = dfs(s, t, INF);
		if(flow == 0) {
			printf("%d\n", ans); return;
		}
		ans += flow;
	}
}

int main(void)
{
	int M, N;
	while(scanf("%d%d", &M, &N) != EOF) {
		memset(h, -1, sizeof(h));
		memset(num, 0, sizeof(num));
		edge_cnt = 0;
		for(int i = 1; i <= M; ++i) scanf("%d", &a[i]);
		int m, v, c, sum, p;
		for(int i = 1; i <= N; ++i) {
			scanf("%d", &m);
			sum = 0; p = 0;
			while(m--) {
				scanf("%d", &v);
				if(num[v]) tmp[p++] = num[v];
				else {
					sum += a[v];
					num[v] = i;
				}
			}
			sort(tmp, tmp+p);
			p = unique(tmp, tmp+p)-tmp;
			for(int j = 0; j < p; ++j) add(tmp[j], i, INF);
			scanf("%d", &c);
			if(sum != 0)  add(0, i, sum);
			add(i, N+1, c);
		}
		ford(0, N+1);
	}
	return 0;
}