posts - 7,comments - 3,trackbacks - 0
PIGS
Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 10566Accepted: 4622

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 arives, 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


最大流,构图思想:用人当点,因为每个人是按顺序的,所以第i个人第一次打开第k个猪圈,第j个人第二次打开第k个猪圈时,相当于第i个人向第j个人增流。
所以,如果第i个人持有第k个猪圈的钥匙,如果是第一次打开,就从源点引边向该点,边权累加猪圈的值(一个人可能持有多个钥匙,所以要累加),如果不是第一次,那么从上一次那个人引出一条无限大的边到i点作为增流。每个点到汇点的权值是该人需要的个数,最大流一次就行了。
SAP,时间很好看。
代码:
#include<stdio.h>
#include<string.h>
#include
<iostream>
#include
<queue>
#define N 1010
using namespace std;
const int maxnode=60000;
const int maxedge=320000;
const int  inf = 1 << 30;
int S,T,cnt,n,m;
int head[maxnode],gap[maxnode],pre[maxnode],cur[maxnode],dis[maxnode];
struct Edge
{
    
int S,t;
    
int next;
    
int w;
}st[maxedge];
void init()
{
    memset(head,
-1,sizeof(head));
    cnt
=0;
}
void AddEdge(int S,int t,int w)
{
    st[cnt].S
=S;
    st[cnt].t
=t;
    st[cnt].w
=w;
    st[cnt].next
=head[S];
    head[S]
=cnt;
    cnt
++;
    st[cnt].S
=t;
    st[cnt].t
=S;
    st[cnt].w
=0;
    st[cnt].next
=head[t];
    head[t]
=cnt;
    cnt
++;
}
void bfs()
{
    memset(gap,
0,sizeof(gap));
    memset(dis,
-1,sizeof(dis));
    queue
<int >Q;
    Q.push(T);
    dis[T]
=0;
    gap[
0]=1;
    
int k,t;
    
while(!Q.empty())
    {
        k
=Q.front();
        Q.pop();
        
for(int i=head[k];i!=-1;i=st[i].next)
        {
            t
=st[i].t;
            
if(dis[t]==-1&&st[i^1].w>0)
            {
                dis[t]
=dis[k]+1;
                gap[dis[t]]
++;
                Q.push(t);
            }
        }
    }
}
int sap()
{
    
int i;
    
for( i=S;i<=T;i++)cur[i]=head[i];
    pre[S]
=S;
    
int u=S,v;
    
int  flow=0;
    
int aug=inf;
    
bool flag;
    
while(dis[S]<=T)
    {
        flag
=false;
        
for( i=cur[u];i!=-1;i=st[i].next)
        {
            v
=st[i].t;
            
if(st[i].w>0&&dis[u]==dis[v]+1)
            {
                cur[u]
=i;
                flag
=true;
                pre[v]
=u;
                aug
=(aug>st[i].w)?st[i].w:aug;
                u
=v;
                
if(v==T)
                {
                    flow
+=aug;
                    
for(u=pre[u];v!=S;u=pre[u])
                    {
                        v
=u;
                        st[cur[u]].w
-=aug;
                        st[cur[u]
^1].w+=aug;
                    }
                    aug
=inf;
                }
                
break;
            }
        }
        
if(flag==true)continue;
        
int mint=T;
        
for( i=head[u];i!=-1;i=st[i].next)
        {
            v
=st[i].t;
            
if(st[i].w>0&&mint>dis[v])
            {
                cur[u]
=i;
                mint
=dis[v];
            }
        }
        gap[dis[u]]
--;
        
if(gap[dis[u]]==0)break;
        gap[dis[u]
=mint+1]++;
        u
=pre[u];
        
if(u==S)aug=inf;
    }
    
return flow;
}

int main()
{
    
int map[N][N];
    
int num[N];
    
int f[N];
    
while (scanf("%d%d"&m, &n) != EOF)
    {
        memset(map, 
0sizeof(map));
        memset(f, 
0sizeof(f));
        init();
        S 
= 0;
        T 
= n + 1;
        
for (int i = 1; i <= m; ++i)
            scanf(
"%d"&num[i]);
        
for (int i = 1; i <= n; ++i)
        {
            
int a, b;
            scanf(
"%d"&a);
            
for (int j = 1; j <= a; ++j)
            {
                
int x;
                scanf(
"%d"&x);
                
if (f[x] == 0)
                {
                    map[S][i] 
+= num[x];
                    f[x] 
= i;
                }
                
else
                {
                    map[f[x]][i] 
= inf;
                    f[x] 
= i;
                }
            }
            scanf(
"%d"&b);
            map[i][T] 
+= b;
        }
        
for (int i = S; i <= T; ++i)
            
for (int j = S; j <= T; ++j)
            
if (map[i][j])
            {
                
//printf("%d %d %d\n", i, j, map[i][j]);
                AddEdge(i, j, map[i][j]);
            }
        bfs();
        printf(
"%d\n", sap());
    }
}

/*
4 2
1 2 3 5
3 1 2 3 10
1 4 5

*/
posted on 2011-10-15 22:12 LLawliet 阅读(147) 评论(0)  编辑 收藏 引用 所属分类: 网络流

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理