poj 1149 PIGS 最大流

PIGS
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 12924   Accepted: 5721

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;
}

 

posted @ 2012-12-10 19:06  yefeng1627  阅读(136)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor