poj 1149 PIGS 最大流
PIGS
Description Mirko works on a pig farm that consists of M locked pig-houses and Mirko can't unlock any pighouse because he doesn't have the keys. Customers come to the farm one after another. Each of them has keys to some pig-houses and wants to buy a certain number of pigs.
All data concerning customers planning to visit the farm on that particular day are available to Mirko early in the morning so that he can make a sales-plan in order to maximize the number of pigs sold. More precisely, the procedure is as following: the customer arrives, opens all pig-houses to which he has the key, Mirko sells a certain number of pigs from all the unlocked pig-houses to him, and, if Mirko wants, he can redistribute the remaining pigs across the unlocked pig-houses. An unlimited number of pigs can be placed in every pig-house. Write a program that will find the maximum number of pigs that he can sell on that day. Input The first line of input contains two integers M and N, 1 <= M <= 1000, 1 <= N <= 100, number of pighouses and number of customers. Pig houses are numbered from 1 to M and customers are numbered from 1 to N.
The next line contains M integeres, for each pig-house initial number of pigs. The number of pigs in each pig-house is greater or equal to 0 and less or equal to 1000. The next N lines contains records about the customers in the following form ( record about the i-th customer is written in the (i+2)-th line): A K1 K2 ... KA B It means that this customer has key to the pig-houses marked with the numbers K1, K2, ..., KA (sorted nondecreasingly ) and that he wants to buy B pigs. Numbers A and B can be equal to 0. Output The first and only line of the output should contain the number of sold pigs.
Sample Input 3 3 3 1 10 2 1 2 2 2 1 3 3 1 2 6 Sample Output 7 Source |
解题思路:
本题关键是如何构造一个容量网络,
1. 将顾客看作除源点和汇点外的节点,并且另设两个节点:源点和汇点。
2.源点和每个猪圈的第1个顾客连边,边的权是开始时猪圈中猪的数量。
3.若源点和某个节点之间有重边,则将权合并(因此源点流出的流量就是所有的猪圈能提供猪的数目,优化成只有100个顶点,这个是非常好的)
4.顾客j紧跟着顾客i之后打开某个猪圈,则边<i,j>的权为无穷大;这是因为,如果顾客j紧跟在顾客i之后打开某个猪圈,那么迈克就有可能根据
顾客j的需求将其他猪圈中的猪调整到该猪圈,这样顾客j就能买到尽可能多的猪.
5.每个顾客和汇点之间连边,边的权是顾客希望购买猪的数目(因此汇点的流入量就是每个股哭所购买的猪的数目)
实现代码:
增广路算法,预流推进 皆可(因为顶点数目最多为102)
参考代码:
SAP:shortest augment path
View Code
#include<stdio.h> #include<string.h> #include<stdlib.h> #define MIN(a,b) (a)<(b)?(a):(b) const int M = 110; const int inf = 0x3fffffff; int n, m, A[1010], pre[1010]; int remain[M][M], h[M], vh[M], S, T, N; void input() { S = 0; T = n+1; N = n+2; memset( pre, 0, sizeof(pre) ); memset( remain, 0, sizeof(remain)); for(int i = 1; i <= m; i++) scanf("%d", &A[i]); int a, k, b; for(int i = 1; i <= n; i++) { scanf("%d", &a); for(int j = 1; j <= a; j++) { scanf("%d", &k ); if( pre[k] == 0 ){ //源点与第一个打开某猪圈的顾客连边 remain[S][i] = remain[S][i] ? (remain[S][i]+A[k]) : A[k]; pre[k] = i; } else{ int u = pre[k]; //相邻两个打开某猪圈连边 remain[u][i] = inf; pre[k] = i; } } scanf("%d", &b); //每个顾客与汇点连边 remain[i][T] = b; } } int DFS( int u, int flow ) { if( u == T ) return flow;//找到增广路 int tmp = h[u]+1, sum = flow; //更新当前点层数 for(int v = 0; v < N; v++) { if( remain[u][v] && h[u] == h[v]+1 ) //允许弧,且一层差别 { int p = DFS( v, MIN( sum, remain[u][v]) ); remain[u][v] -= p; remain[v][u] += p; sum -= p; //更新残留网络 if( sum == 0 || h[S] == N ) return flow-sum; } } for(int v = 0; v < N; v++) if( remain[u][v] ) tmp = MIN( tmp, h[v] ); if( !( --vh[ h[u] ] ) ) h[S] = N; //间隙优化,当出现断层即可判定无增广路 else ++vh[ h[u] = tmp+1 ]; return flow-sum; } void sap() { int maxflow = 0; memset( h, 0, sizeof(h)); memset( vh, 0, sizeof(vh)); vh[S] = N; //0层节点数量为N while( h[S] < N ) maxflow += DFS( S, inf ); printf("%d\n", maxflow ); } int main() { while( scanf("%d%d", &m, &n) != EOF) { input(); sap(); } return 0; }