POJ 1149 PIGS

PIGS
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 20579   Accepted: 9387

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

[Submit]   [Go Back]   [Status]   [Discuss]

 

网络流——流量传递类型。

 

四月份的时候曾经写过一遍,但是已然忘光了,所以只得重新来过。

 

错误的建图方法

看到题之后有个简单的建图想法,就是设立M*N个猪圈点,以及N个商人点,如下建图:

源点向第一排M个猪圈点连容量为初始猪数目的边,代表一开始猪圈中最多存在的猪。

每排M个猪圈点中,A个能被打开的猪圈点向商人点连容量为无穷的边,代表可以被打开。

每排的商人点向汇点连容量为商人购买数目B的边,表示这个人的最大购买限度。

每排的商人点向下一排的A个点(这A个点还是本排商人能打开的猪圈)连无穷边,代表猪可以自由转移。

当然,因为猪也可以待在猪圈里不动,所以每排的各个猪圈向下一排的该猪圈连无穷边。

这样跑最大流,显然可以得到最优解,但是点的数量是O(N*M)的,而边的数量是……(懒得想了),果不其然地TLE了。

 

#include <cstdio>
#include <cstring>

inline int get_c(void)
{
    static const int siz = 1024;

    static char buf[siz];
    static char *head = buf + siz;
    static char *tail = buf + siz;

    if (head == tail)
        fread(head = buf, 1, siz, stdin);

    return *head++;
}

inline int get_i(void)
{
    register int ret = 0;
    register int neg = false;
    register int bit = get_c();

    for (; bit < 48; bit = get_c())
        if (bit == '-')neg ^= true;

    for (; bit > 47; bit = get_c())
        ret = ret * 10 + bit - 48;

    return neg ? -ret : ret;
}

template <class T>
inline T min(T a, T b)
{
    return a < b ? a : b;
}

const int inf = 2e9;
const int maxn = 500005;

int n, m;
int s, t;
int edges;
int hd[maxn];
int to[maxn];
int nt[maxn];
int fl[maxn];

inline void add(int u, int v, int f)
{    //printf("add %d %d %d\n", u, v, f);
    nt[edges] = hd[u]; to[edges] = v; fl[edges] = f; hd[u] = edges++;
    nt[edges] = hd[v]; to[edges] = u; fl[edges] = 0; hd[v] = edges++;
}

int dep[maxn];

inline bool bfs(void)
{
    static int que[maxn];
    static int head, tail;
    
    memset(dep, 0, sizeof(dep));
    head = 0, tail = 0;
    que[tail++] = s;
    dep[s] = 1;
    
    while (head != tail)
    {
        int u = que[head++], v;
        for (int i = hd[u]; ~i; i = nt[i])
            if (!dep[v = to[i]] && fl[i])
            {
                dep[v] = dep[u] + 1;
                que[tail++] = v;
            }
    }
    
    return dep[t] != 0;
}

int dfs(int u, int f)
{
    if (u == t || !f)
        return f;
        
    int used = 0, flow, v;
    
    for (int i = hd[u]; ~i; i = nt[i])
        if (dep[v = to[i]] == dep[u] + 1 && fl[i])
        {
            flow = dfs(v, min(f - used, fl[i]));
            
            used += flow;
            fl[i] -= flow;
            fl[i^1] += flow;
            
            if (used == f)
                return f;
        }
        
    if (!used)
        dep[u] = 0;
        
    return used;
}

inline int maxFlow(void)
{
    int maxFlow = 0, newFlow;
    
    while (bfs())
        while (newFlow = dfs(s, inf))
            maxFlow += newFlow;
            
    return maxFlow;
}

signed main(void)
{
    n = get_i();
    m = get_i();
        
    s = 0, t = (n + 1) * m + 1;
        
    memset(hd, -1, sizeof(hd));
    
    for (int i = 1; i <= n; ++i)
    {
        int pigs = get_i();
        add(s, i, pigs);
    }
    
    for (int i = 1; i < m; ++i)
        for (int j = 1; j <= n; ++j)
            add((n + 1)*(i - 1) + j, (n + 1)*i + j, inf);
    
    for (int i = 1; i <= m; ++i)
    {
        int k = get_i();
        for (int j = 1; j <= k; ++j)
        {
            int p = get_i();
            add((n + 1)*(i - 1) + p, (n + 1)*i, inf);
            add((n + 1)*i, (n + 1)*i + p, inf);
        }
        add((n + 1)*i, t, get_i());
    }
    
    printf("%d\n", maxFlow());
}

 

 

正确的建图方法

设置一个源点,向M个猪圈点连初始数目的边,代表一开始的猪的数目。

然后想办法简化猪圈之间的转移,着重商人能得到的猪的来源,考虑直接在商人之间进行转移。

易知,如果商人X和商人Y,有X比Y先来,且X和Y有公共的猪圈的钥匙,那么Y能享受X能到达的所有猪圈。

用last_i表示上一个可以打开i猪圈的点,初始last_i=i猪圈初始点。

一个商人,如果有猪圈k的钥匙,那么last_k的所有流量都可以向这个商人转移,所有从last_k向商人连边,同时把last_k设为该商人。

商人点向汇点连最大购买数量的边。

跑最大流即可,点数O(N+M),边数O(N+M),小菜一碟了。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 
  4 inline int get_c(void)
  5 {
  6     static const int siz = 1024;
  7 
  8     static char buf[siz];
  9     static char *head = buf + siz;
 10     static char *tail = buf + siz;
 11 
 12     if (head == tail)
 13         fread(head = buf, 1, siz, stdin);
 14 
 15     return *head++;
 16 }
 17 
 18 inline int get_i(void)
 19 {
 20     register int ret = 0;
 21     register int neg = false;
 22     register int bit = get_c();
 23 
 24     for (; bit < 48; bit = get_c())
 25         if (bit == '-')neg ^= true;
 26 
 27     for (; bit > 47; bit = get_c())
 28         ret = ret * 10 + bit - 48;
 29 
 30     return neg ? -ret : ret;
 31 }
 32 
 33 template <class T>
 34 inline T min(T a, T b)
 35 {
 36     return a < b ? a : b;
 37 }
 38 
 39 const int inf = 2e9;
 40 const int maxn = 500005;
 41 
 42 int n, m;
 43 int s, t;
 44 int edges;
 45 int hd[maxn];
 46 int to[maxn];
 47 int nt[maxn];
 48 int fl[maxn];
 49 
 50 inline void add(int u, int v, int f)
 51 {    //printf("add %d %d %d\n", u, v, f);
 52     nt[edges] = hd[u]; to[edges] = v; fl[edges] = f; hd[u] = edges++;
 53     nt[edges] = hd[v]; to[edges] = u; fl[edges] = 0; hd[v] = edges++;
 54 }
 55 
 56 int dep[maxn];
 57 
 58 inline bool bfs(void)
 59 {
 60     static int que[maxn];
 61     static int head, tail;
 62     
 63     memset(dep, 0, sizeof(dep));
 64     head = 0, tail = 0;
 65     que[tail++] = s;
 66     dep[s] = 1;
 67     
 68     while (head != tail)
 69     {
 70         int u = que[head++], v;
 71         for (int i = hd[u]; ~i; i = nt[i])
 72             if (!dep[v = to[i]] && fl[i])
 73             {
 74                 dep[v] = dep[u] + 1;
 75                 que[tail++] = v;
 76             }
 77     }
 78     
 79     return dep[t] != 0;
 80 }
 81 
 82 int dfs(int u, int f)
 83 {
 84     if (u == t || !f)
 85         return f;
 86         
 87     int used = 0, flow, v;
 88     
 89     for (int i = hd[u]; ~i; i = nt[i])
 90         if (dep[v = to[i]] == dep[u] + 1 && fl[i])
 91         {
 92             flow = dfs(v, min(f - used, fl[i]));
 93             
 94             used += flow;
 95             fl[i] -= flow;
 96             fl[i^1] += flow;
 97             
 98             if (used == f)
 99                 return f;
100         }
101         
102     if (!used)
103         dep[u] = 0;
104         
105     return used;
106 }
107 
108 inline int maxFlow(void)
109 {
110     int maxFlow = 0, newFlow;
111     
112     while (bfs())
113         while (newFlow = dfs(s, inf))
114             maxFlow += newFlow;
115             
116     return maxFlow;
117 }
118 
119 int last[maxn];
120 
121 signed main(void)
122 {
123     n = get_i();
124     m = get_i();
125         
126     s = 0, t = n + m + 1;
127         
128     memset(hd, -1, sizeof(hd));
129     
130     for (int i = 1; i <= n; ++i)
131         add(s, i, get_i()), last[i] = i;
132         
133     for (int i = 1; i <= m; ++i)
134     {
135         for (int j = get_i(), k; j--; )
136             k = get_i(), add(last[k], n + i, inf), last[k] = n + i;
137         add(n + i, t, get_i());
138     }
139     
140     printf("%d\n", maxFlow());
141 }

 

@Author: YouSiki

posted @ 2016-12-29 14:37  YouSiki  阅读(114)  评论(0编辑  收藏  举报