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

 

让源点和每个猪圈的第一个用户相连,容量是猪圈的猪的数量,将一个猪圈的i用户与其紧接的下一个用户连接,容量是无穷,因为下一个用户可以要求分布将上一个已经打开的猪圈,而且也不知道加几只,设为无穷,最后将客户和会点相连,容量为客户的需求量,不知道自己的解释清不清楚

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#define oo 1<<28
using namespace std;
int n,m,map[300][300];
int a[300],p[300],flow[300][300];
int pig[1000],num[1000],q[1000];
int start,end;
void init()
{
    memset(num,0,sizeof(num));
    memset(map,0,sizeof(map));
    memset(flow,0,sizeof(flow));
    memset(q,0,sizeof(q));
}
int EK()
{
    int u,v;
    queue<int>q;
    memset(flow,0,sizeof(flow));
    memset(p,0,sizeof(p));
    int f=0;
    while(1)
    {
        memset(a,0,sizeof(a));
        a[start]=oo;//oo是因为起点没有节点控制,先初始为最
        q.push(start);
        while(!q.empty())//bfs找增广路
        {
            int u=q.front();
            q.pop();
            for(v=1; v<=n; v++)
            {
                if(!a[v]&&map[u][v]>flow[u][v])//找到新节点,保证要流过的小于最大界限
                {
                    p[v]=u;
                    q.push(v);
                    a[v]=a[u]<map[u][v]-flow[u][v]?a[u]:map[u][v]-flow[u][v];//最小残量,保证此增光路上每一条都可通过,否则就成了死路
                }
            }
        }
        if(a[end]==0)
            break;
        for(u=end; u!=start; u=p[u]) //从汇点向回流
        {
            flow[p[u]][u]+=a[end];//正向的加上此增广路上最小的值
            flow[u][p[u]]-=a[end];//同样反向的要减去
        }
        f+=a[end];
    }
    return f;
}
int main()
{
    int i,j,t,k,a,b,x,y;
    while(~scanf("%d%d",&m,&n))
    {
        init();
        int u,v,w;
        for(i=1; i<=m; i++)
        {
            scanf("%d",&pig[i]);
        }
        for(i=1; i<=n; i++)
        {
            scanf("%d",&k);
            for(j=1; j<=k; j++)
            {
                scanf("%d",&x);
                num[x]++;
                if(num[x]==1)
                {
                    map[0][i]+=pig[x];//将源点和每个猪圈的第一个用户相连,因为他们是有顺序选择的
                    q[x]=i;//记录当前此猪圈的被选用户
                }
                else
                {
                    t=q[x];
                    map[t][i]=oo;//将此猪圈的之前用户和此用户相连,权值为无穷,因为主人可以将之前的赶到这个猪圈
                    q[x]=i;//依然记录当前用户信息
                }
            }
            scanf("%d",&y);
            map[i][n+1]=y;//最后将每个客户和结束点相连,权值为客户需要
        }
        start=0,end=++n;//开始于1,结束于m
        printf("%d\n",EK());
    }
    return 0;
}


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值