zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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
    ", 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
    ", maxFlow());
    141 }

    @Author: YouSiki

  • 相关阅读:
    有种感觉叫失去才知道珍惜
    Alternativa 3D Series – Tutorial 1 – Getting Started
    ruby中使用MiniMagick处理图片
    RMagick动态生成图片
    Rails Model验证之强大
    Rails验证信息的中文化
    Prawn:Ruby生成PDF更简捷的选择
    ruby gem相关命令使用
    Ruby Gems(1)–简要介绍和ruby on rails安装
    Rails安装
  • 原文地址:https://www.cnblogs.com/yousiki/p/6232899.html
Copyright © 2011-2022 走看看