pku 1149最大流(标号法)
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 }