1 /*
2 * 一般增广路算法--Ford_Fulkerson算法(标号法)
3 */
4 /*
5 建图:将顾客看作除源点和汇点以外的节点,源点和每个猪圈的第一个顾客连边,边的权是开始时猪
6 圈中猪的数目,若源点和某个节点之间有重边,则将权合并,顾客j紧跟在顾客i之后打开某个猪圈,
7 则边<i,j>的权是+∞,每个顾客和汇之间连边,边的权是顾客所希望购买的猪的数目。
8 */
9
10 #include <cstdio>
11 #include <cstring>
12 #include <iostream>
13
14 using namespace std;
15
16 const int N = 100;
17 const int M = 1000;
18 const int INF = 1000000000;
19
20 int vs, vt; //源点与汇点
21 int front, rear; //队列头与尾
22 int Q[N+2]; //队列
23 int prev[N+2]; //标号法的第一个分量
24 int minflow[N+2]; //标号法的第二个分量
25 int flow[N+2][N+2]; //节点之间的流量
26 int customer[N+2][N+2];//节点之间的容量
27 int house[M]; //存储每个猪圈中猪的数目
28 int last[M]; //存储每个猪圈的前一个顾客的序号
29
30 void buildFlow() { //建图
31 int n, m, num, k;
32 memset(last, 0, sizeof(last));
33 memset(customer, 0, sizeof(customer));
34 scanf ("%d%d", &m, &n);
35 vs = 0, vt = n + 1; //源点与汇点的编号
36 for (int i=1; i<=m; ++i) scanf ("%d", &house[i]);
37 for (int i=1; i<=n; ++i) {
38 scanf ("%d", &num);
39 for (int j=1; j<=num; ++j) {
40 scanf ("%d", &k);
41 if (last[k] == 0) customer[vs][i] += house[k];//第i个顾客是第k个猪圈的第1个顾客
42 else customer[last[k]][i] = INF;//表示顾客i紧跟顾客last[k]后面打开第k个猪圈
43 last[k] = i;
44 }
45 scanf ("%d", &customer[i][vt]);//每个顾客到汇点的边,权值为顾客购买猪的数目
46 }
47 }
48
49 int Ford_Fulkerson() {
50 int v, p;
51 for (int i=0; i<N+2; ++i) {//构造零流,从零流开始标号调整
52 for (int j=0; j<N+2; ++j) flow[i][j] = 0;
53 }
54 minflow[0] = INF; //源点标号的第2个分量为无穷大
55 while (1) { //标号法,采用BFS的思想遍历网络,从而对所有顶点进行标号
56 for (int i=0; i<N+2; ++i) prev[i] = -2;//每次标号前,每个顶点重新回到未标号状态
57 prev[0] = -1; //源点的标号为-1
58 front = rear = 0;
59 Q[front++] = 0;
60 while (rear<front && prev[vt]==-2) {//标号过程
61 v = Q[rear++];
62 for (int i=0; i<vt+1; ++i) {
63 if (prev[i]==-2 && (p=customer[v][i]-flow[v][i])) {
64 prev[i] = v;
65 Q[front++] = i;
66 minflow[i] = (minflow[v] < p) ? minflow[v] : p;
67 }
68 }
69 }
70 if (prev[vt] == -2) break;//汇点vt没有标号,标号法结束
71 int i, j;
72 for (i=prev[vt], j=vt; i!=-1; j=i, i=prev[i]) {//调整过程
73 flow[i][j] += minflow[vt];
74 flow[j][i] -= minflow[vt];
75 }
76 }
77 p = 0;
78 for (int i=0; i<vt; ++i) p += flow[i][vt];//统计进入汇点的流量,即为最大流的流量
79 return p;
80 }
81
82 int main() {
83 buildFlow();
84 int ans = Ford_Fulkerson();
85 printf ("%d\n", ans);
86 return 0;
87 }