• POJ3189 Steady Cow Assignment —— 二分图多重匹配/最大流 + 二分


    题目链接:https://vjudge.net/problem/POJ-3189

    Steady Cow Assignment
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 6979   Accepted: 2418

    Description

    Farmer John's N (1 <= N <= 1000) cows each reside in one of B (1 <= B <= 20) barns which, of course, have limited capacity. Some cows really like their current barn, and some are not so happy. 

    FJ would like to rearrange the cows such that the cows are as equally happy as possible, even if that means all the cows hate their assigned barn. 

    Each cow gives FJ the order in which she prefers the barns. A cow's happiness with a particular assignment is her ranking of her barn. Your job is to find an assignment of cows to barns such that no barn's capacity is exceeded and the size of the range (i.e., one more than the positive difference between the the highest-ranked barn chosen and that lowest-ranked barn chosen) of barn rankings the cows give their assigned barns is as small as possible.

    Input

    Line 1: Two space-separated integers, N and B 

    Lines 2..N+1: Each line contains B space-separated integers which are exactly 1..B sorted into some order. The first integer on line i+1 is the number of the cow i's top-choice barn, the second integer on that line is the number of the i'th cow's second-choice barn, and so on. 

    Line N+2: B space-separated integers, respectively the capacity of the first barn, then the capacity of the second, and so on. The sum of these numbers is guaranteed to be at least N.

    Output

    Line 1: One integer, the size of the minumum range of barn rankings the cows give their assigned barns, including the endpoints.

    Sample Input

    6 4
    1 2 3 4
    2 3 1 4
    4 2 3 1
    3 1 2 4
    1 3 4 2
    1 4 2 3
    2 1 3 2

    Sample Output

    2

    Hint

    Explanation of the sample: 

    Each cow can be assigned to her first or second choice: barn 1 gets cows 1 and 5, barn 2 gets cow 2, barn 3 gets cow 4, and barn 4 gets cows 3 and 6.

    Source

    题解:

    题意:有n头牛, 安排到m个牲棚里住。每头牛对每个牲棚都有一个好感度排名。主人为了使得这些牛尽可能满意,规定了获得最低好感度的牛和获得最高好感度的牛的好感度差值最小(即好感度跨度最小)。

    1.二分跨度。然后对于每个跨度,枚举最低好感度(最高好感度也就可以求出),然后开始建图:如果某头牛对某个牲棚的好感度在这个范围内,则连上边;否则不连。

    2.用二分图多重匹配或者最大流,求出是否每头牛都可以被安排到某个牲棚中。如果可以,则缩小跨度,否则增大跨度。

    多重匹配:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <string>
     6 #include <vector>
     7 #include <map>
     8 #include <set>
     9 #include <queue>
    10 #include <sstream>
    11 #include <algorithm>
    12 using namespace std;
    13 const int INF = 2e9;
    14 const int MOD = 1e9+7;
    15 const int MAXM = 20+10;
    16 const int MAXN = 1e3+10;
    17 
    18 int uN, vN, Rank[MAXN][MAXM];
    19 int num[MAXM], linker[MAXM][MAXN];
    20 bool g[MAXN][MAXM], used[MAXM];
    21 
    22 bool dfs(int u)
    23 {
    24     for(int v = 1; v<=vN; v++)
    25     if(g[u][v] && !used[v])
    26     {
    27         used[v] = true;
    28         if(linker[v][0]<num[v])
    29         {
    30             linker[v][++linker[v][0]] = u;
    31             return true;
    32         }
    33         for(int i = 1; i<=num[v]; i++)
    34         if(dfs(linker[v][i]))
    35         {
    36             linker[v][i] = u;
    37             return true;
    38         }
    39     }
    40     return false;
    41 }
    42 
    43 bool hungary()
    44 {
    45     for(int i = 1; i<=vN; i++)
    46         linker[i][0] = 0;
    47     for(int u = 1; u<=uN; u++)
    48     {
    49         memset(used, false, sizeof(used));
    50         if(!dfs(u)) return false;
    51     }
    52     return true;
    53 }
    54 
    55 bool test(int mid)
    56 {
    57     for(int down = 1; down<=vN-mid+1; down++)
    58     {
    59         int up = down+mid-1;
    60         memset(g, false, sizeof(g));
    61         for(int i = 1; i<=uN; i++)
    62         for(int j = down; j<=up; j++)
    63                 g[i][Rank[i][j]] = true;
    64 
    65         if(hungary()) return true;
    66     }
    67     return false;
    68 }
    69 
    70 int main()
    71 {
    72     while(scanf("%d%d", &uN, &vN)!=EOF)
    73     {
    74         for(int i = 1; i<=uN; i++)
    75         for(int j = 1; j<=vN; j++)
    76             scanf("%d", &Rank[i][j]);
    77 
    78         for(int i = 1; i<=vN; i++)
    79             scanf("%d", &num[i]);
    80 
    81         int l = 1, r = vN;
    82         while(l<=r)
    83         {
    84             int mid = (l+r)>>1;
    85             if(test(mid))
    86                 r = mid - 1;
    87             else
    88                 l = mid + 1;
    89         }
    90         printf("%d
    ", l);
    91     }
    92 }
    View Code

    最大流:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <string>
      6 #include <vector>
      7 #include <map>
      8 #include <set>
      9 #include <queue>
     10 #include <sstream>
     11 #include <algorithm>
     12 using namespace std;
     13 const int INF = 2e9;
     14 const int MOD = 1e9+7;
     15 const int MAXM = 20+10;
     16 const int MAXN = 2e3+10;
     17 
     18 struct Edge
     19 {
     20     int to, next, cap, flow;
     21 }edge[MAXN*MAXN];
     22 int tot, head[MAXN];
     23 
     24 int uN, vN, Rank[MAXN][MAXM], num[MAXM];
     25 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
     26 
     27 void add(int u, int v, int w)
     28 {
     29     edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
     30     edge[tot].next = head[u]; head[u] = tot++;
     31     edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
     32     edge[tot].next = head[v]; head[v] = tot++;
     33 }
     34 
     35 int sap(int start, int end, int nodenum)
     36 {
     37     memset(dep, 0, sizeof(dep));
     38     memset(gap, 0, sizeof(gap));
     39     memcpy(cur, head, sizeof(head));
     40     int u = pre[start] = start, maxflow = 0,aug = INF;
     41     gap[0] = nodenum;
     42     while(dep[start]<nodenum)
     43     {
     44         loop:
     45         for(int i = cur[u]; i!=-1; i = edge[i].next)
     46         {
     47             int v = edge[i].to;
     48             if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+1)
     49             {
     50                 aug = min(aug, edge[i].cap-edge[i].flow);
     51                 pre[v] = u;
     52                 cur[u] = i;
     53                 u = v;
     54                 if(v==end)
     55                 {
     56                     maxflow += aug;
     57                     for(u = pre[u]; v!=start; v = u,u = pre[u])
     58                     {
     59                         edge[cur[u]].flow += aug;
     60                         edge[cur[u]^1].flow -= aug;
     61                     }
     62                     aug = INF;
     63                 }
     64                 goto loop;
     65             }
     66         }
     67         int mindis = nodenum;
     68         for(int i = head[u]; i!=-1; i = edge[i].next)
     69         {
     70             int v=edge[i].to;
     71             if(edge[i].cap-edge[i].flow && mindis>dep[v])
     72             {
     73                 cur[u] = i;
     74                 mindis = dep[v];
     75             }
     76         }
     77         if((--gap[dep[u]])==0)break;
     78         gap[dep[u]=mindis+1]++;
     79         u = pre[u];
     80     }
     81     return maxflow;
     82 }
     83 
     84 bool test(int mid)
     85 {
     86     for(int down = 1; down<=vN-mid+1; down++)
     87     {
     88         tot = 0;
     89         memset(head, -1, sizeof(head));
     90         for(int i = 1; i<=uN; i++)
     91         {
     92             add(0, i, 1);
     93             int up = down+mid-1;
     94             for(int j = down; j<=up; j++)
     95                 add(i, uN+Rank[i][j], 1);
     96         }
     97         for(int i = 1; i<=vN; i++)
     98             add(uN+i, uN+vN+1, num[i]);
     99 
    100         int maxflow = sap(0, uN+vN+1, uN+vN+2);
    101         if(maxflow==uN) return true;
    102     }
    103     return false;
    104 }
    105 
    106 int main()
    107 {
    108     while(scanf("%d%d", &uN, &vN)!=EOF)
    109     {
    110         for(int i = 1; i<=uN; i++)
    111         for(int j = 1; j<=vN; j++)
    112             scanf("%d", &Rank[i][j]);
    113 
    114         for(int i = 1; i<=vN; i++)
    115             scanf("%d", &num[i]);
    116 
    117         int l = 1, r = vN;
    118         while(l<=r)
    119         {
    120             int mid = (l+r)>>1;
    121             if(test(mid))
    122                 r = mid - 1;
    123             else
    124                 l = mid + 1;
    125         }
    126         printf("%d
    ", l);
    127     }
    128 }
    View Code
  • 相关阅读:
    简单的JAVAWeb选课系统
    公文流转系统001
    第九周动手动脑
    JAVA文件操作
    动手动脑-异常处理
    个人NABCD
    水王(课堂作业)
    软件学习进度表07
    软件工程学习进度表06
    软件工程个人作业05(二维数组求最大子数组的和)
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7825303.html
Copyright © 2020-2023  润新知