1149-PIGS(网络流建模,缩点)

来源:互联网 发布:电子地图综合搜索软件 编辑:程序博客网 时间:2024/06/05 17:31
PIGS
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 18057 Accepted: 8210

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 33 1 102 1 2 22 1 3 31 2 6

Sample Output

7

Source

Croatia OI 2002 Final Exam - First day

题意: 有M个猪圈,每个猪圈里初始时有若干头猪,一开始猪圈都是关闭的. 依次来了N个顾客,每个顾客分别会打开指定的若干个猪圈,从中买若干头猪.每个顾客走后,他打开的那些猪圈中的猪可以被农场主重新分配,然后再关闭猪圈. 问农场主最多能卖出多少头猪.

题解: 这道题目具有很明显的网络流特性. 这道题可以有很多中建模方法,在这里我只介绍一种比较容易理解的建模方法.首先先虚拟出源点和汇点,然后从源点往每一个顾客连一条容量为他们想买的猪数量的边,每个猪圈往汇点连一条容量为猪圈初始猪的数量的边.
           接着对于每一个顾客来说,因为猪圈打开后可以重新任意的分配猪圈的数量,所以对于这些打开的猪圈其实是互相联通的,所以我们可以虚拟出一个节点出来,分别指向这些猪圈,然后顾客往虚拟节点连一条INF的边.比如1号顾客想在1,2,3号猪圈卖猪,则可以虚拟出一个节点a,a->1,a->2,a->3,1->a,这样就可以处理联通的情况. 不过这里有个问题,就是打开的猪圈中有可能全部会被接下来的顾客买走,所以这里我们怎么保证猪圈的连通性会持续到下面的节点呢? 这个容易,可以开一个Hash数组,维护每个猪圈所属的联通块,比如Hasn[1] = a,Hash[2] = a.Hash[3] = a,这样你在接下来访问到的时候,接可以直接访问之前的联通块了.

AC代码:
             
/* ***********************************************Author        :xdloveCreated Time  :2015年07月14日 星期二 14时34分27秒File Name     :a.cpp ************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;typedef long long ll;const int MAXN = 3000;const int MAXM = 1e5 + 5;const int INF = 0x3f3f3f3f;struct Node{    int from,to,next;    int cap;}edge[MAXM * 2];int tol;int Head[MAXN];int que[MAXN];int dep[MAXN]; //dep为点的层次int stack[MAXN];//stack为栈,存储当前增广路int cur[MAXN];//存储当前点的后继void Init(){    tol = 0;    memset(Head,-1,sizeof(Head));}void add_edge(int u, int v, int w){    edge[tol].from = u;    edge[tol].to = v;    edge[tol].cap = w;    edge[tol].next = Head[u];    Head[u] = tol++;    edge[tol].from = v;    edge[tol].to = u;    edge[tol].cap = 0;    edge[tol].next = Head[v];    Head[v] = tol++;}int BFS(int start, int end){    int front, rear;    front = rear = 0;    memset(dep, -1, sizeof(dep));    que[rear++] = start;    dep[start] = 0;    while (front != rear)    {        int u = que[front++];        if (front == MAXN)front = 0;        for (int i = Head[u]; i != -1; i = edge[i].next)        {            int v = edge[i].to;            if (edge[i].cap > 0 && dep[v] == -1)            {                dep[v] = dep[u] + 1;                que[rear++] = v;                if (rear >= MAXN)rear = 0;                if (v == end)return 1;            }        }    }    return 0;}int dinic(int start, int end){    int res = 0;    int top;    while (BFS(start, end))    {        memcpy(cur, Head, sizeof(Head));        int u = start;        top = 0;        while (true)        {            if (u == end)            {                int min = INF;                int loc;                for (int i = 0; i < top; i++)                    if (min > edge[stack[i]].cap)                    {                        min = edge[stack[i]].cap;                        loc = i;                    }                for (int i = 0; i < top; i++)                {                    edge[stack[i]].cap -= min;                    edge[stack[i] ^ 1].cap += min;                }                res += min;                top = loc;                u = edge[stack[top]].from;            }            for (int i = cur[u]; i != -1; cur[u] = i = edge[i].next)                if (edge[i].cap != 0 && dep[u] + 1 == dep[edge[i].to])                    break;            if (cur[u] != -1)            {                stack[top++] = cur[u];                u = edge[cur[u]].to;            }            else            {                if (top == 0)break;                dep[u] = -1;                u = edge[stack[--top]].from;            }        }    }    return res;}int a[MAXN],Hash[MAXN];int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int n,m;    while(~scanf("%d %d",&m,&n))    {        Init();        int s = 0,t = n + m + 1;        int node = t;        for(int i = 1; i <= m; i++)        {            scanf("%d",&a[i]);            Hash[i] = i + n;            add_edge(i + n,t,a[i]);        }        for(int i = 1; i <= n; i++)        {            int x,v;            scanf("%d",&x);            node++;            while(x--)            {                scanf("%d",&v);                add_edge(node,Hash[v],INF);                Hash[v] = node;            }            scanf("%d",&x);            add_edge(s,i,x);            add_edge(i,node,INF);        }        printf("%d\n",dinic(s,t));    }    return 0;}



0 0