您的位置:首页 > 理论基础 > 计算机网络

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

2015-07-28 10:55 597 查看
PIGS
Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 18057Accepted: 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 3
3 1 10
2 1 2 2
2 1 3 3
1 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        :xdlove
Created 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: