• POJ2112 Optimal Milking —— 二分图多重匹配/最大流 + 二分


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

    Optimal Milking
    Time Limit: 2000MS   Memory Limit: 30000K
    Total Submissions: 18555   Accepted: 6626
    Case Time Limit: 1000MS

    Description

    FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) cows. A set of paths of various lengths runs among the cows and the milking machines. The milking machine locations are named by ID numbers 1..K; the cow locations are named by ID numbers K+1..K+C. 

    Each milking point can "process" at most M (1 <= M <= 15) cows each day. 

    Write a program to find an assignment for each cow to some milking machine so that the distance the furthest-walking cow travels is minimized (and, of course, the milking machines are not overutilized). At least one legal assignment is possible for all input data sets. Cows can traverse several paths on the way to their milking machine. 

    Input

    * Line 1: A single line with three space-separated integers: K, C, and M. 

    * Lines 2.. ...: Each of these K+C lines of K+C space-separated integers describes the distances between pairs of various entities. The input forms a symmetric matrix. Line 2 tells the distances from milking machine 1 to each of the other entities; line 3 tells the distances from machine 2 to each of the other entities, and so on. Distances of entities directly connected by a path are positive integers no larger than 200. Entities not directly connected by a path have a distance of 0. The distance from an entity to itself (i.e., all numbers on the diagonal) is also given as 0. To keep the input lines of reasonable length, when K+C > 15, a row is broken into successive lines of 15 numbers and a potentially shorter line to finish up a row. Each new row begins on its own line. 

    Output

    A single line with a single integer that is the minimum possible total distance for the furthest walking cow. 

    Sample Input

    2 3 2
    0 3 2 1 1
    3 0 3 2 0
    2 3 0 1 0
    1 2 1 0 2
    1 0 0 2 0
    

    Sample Output

    2
    

    Source

    题解:

    题意:有n头牛, m个挤奶器(只能为个数限定的牛挤奶)。每头牛和挤奶器都有其固定的位置。主人安排每头牛去某个挤奶器中挤奶,且在途中,牛可以经过其他地方。为了节省牛的体力,主人希望路途最长的那头牛的路途尽可能短(最大值最小)。

    1.用Floyd算法求出每头牛到每个挤奶器的最短路径。

    2.二分最长路径,然后重新建图,如果某条路径的长度小于等于最长路径,则连起两端点;否则,两端点没有连接。

    3.利用二分图多重匹配或者最大流,求出是否每头牛都能在某台挤奶器中挤奶。如果可以,则减小最长路径;否则增大最长路径。

    多重匹配:

     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 = 5e2+10;
    16 const int MAXN = 4e2+10;
    17 
    18 int uN, vN, m, N, maze[MAXN][MAXN];
    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(int mid)
    44 {
    45     memset(g, false, sizeof(g));
    46     for(int i = vN+1; i<=N; i++)
    47         for(int j = 1; j<=vN; j++)
    48             if(maze[i][j]<=mid)
    49                 g[i][j] = true;
    50 
    51     for(int i = 1; i<=vN; i++)
    52     {
    53         num[i] = m;
    54         linker[i][0] = 0;
    55     }
    56     for(int u = vN+1; u<=N; u++)
    57     {
    58         memset(used, false, sizeof(used));
    59         if(!dfs(u)) return false;
    60     }
    61     return true;
    62 }
    63 
    64 void Flyod()
    65 {
    66     for(int k = 1; k<=N; k++)
    67         for(int i = 1; i<=N; i++)
    68             for(int j = 1; j<=N; j++)
    69                 maze[i][j] = min(maze[i][j], maze[i][k]+maze[k][j]);
    70 }
    71 
    72 int main()
    73 {
    74     while(scanf("%d%d%d", &vN, &uN, &m)!=EOF)
    75     {
    76         N = uN + vN;
    77         for(int i = 1; i<=N; i++)
    78         for(int j = 1; j<=N; j++)
    79         {
    80             scanf("%d", &maze[i][j]);
    81             if(maze[i][j]==0) maze[i][j] = INF/2;
    82         }
    83 
    84         Flyod();
    85         int l = 1, r = 200*400;
    86         while(l<=r)
    87         {
    88             int mid = (l+r)>>1;
    89             if(hungary(mid))
    90                 r = mid - 1;
    91             else
    92                 l = mid + 1;
    93         }
    94         printf("%d
    ", l);
    95     }
    96 }
    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 = 5e2+10;
     16 const int MAXN = 4e2+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, m, N, maze[MAXN][MAXN];
     25 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
     26 void add(int u, int v, int w)
     27 {
     28     edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
     29     edge[tot].next = head[u]; head[u] = tot++;
     30     edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
     31     edge[tot].next = head[v]; head[v] = tot++;
     32 }
     33 
     34 int sap(int start, int end, int nodenum)
     35 {
     36     memset(dep, 0, sizeof(dep));
     37     memset(gap, 0, sizeof(gap));
     38     memcpy(cur, head, sizeof(head));
     39     int u = pre[start] = start, maxflow = 0,aug = INF;
     40     gap[0] = nodenum;
     41     while(dep[start]<nodenum)
     42     {
     43         loop:
     44         for(int i = cur[u]; i!=-1; i = edge[i].next)
     45         {
     46             int v = edge[i].to;
     47             if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+1)
     48             {
     49                 aug = min(aug, edge[i].cap-edge[i].flow);
     50                 pre[v] = u;
     51                 cur[u] = i;
     52                 u = v;
     53                 if(v==end)
     54                 {
     55                     maxflow += aug;
     56                     for(u = pre[u]; v!=start; v = u,u = pre[u])
     57                     {
     58                         edge[cur[u]].flow += aug;
     59                         edge[cur[u]^1].flow -= aug;
     60                     }
     61                     aug = INF;
     62                 }
     63                 goto loop;
     64             }
     65         }
     66         int mindis = nodenum;
     67         for(int i = head[u]; i!=-1; i = edge[i].next)
     68         {
     69             int v=edge[i].to;
     70             if(edge[i].cap-edge[i].flow && mindis>dep[v])
     71             {
     72                 cur[u] = i;
     73                 mindis = dep[v];
     74             }
     75         }
     76         if((--gap[dep[u]])==0)break;
     77         gap[dep[u]=mindis+1]++;
     78         u = pre[u];
     79     }
     80     return maxflow;
     81 }
     82 
     83 bool test(int mid)
     84 {
     85     tot = 0;
     86     memset(head, -1, sizeof(head));
     87     for(int i = vN+1; i<=N; i++)
     88     {
     89         add(0, i, 1);
     90         for(int j = 1; j<=vN; j++)
     91             if(maze[i][j]<=mid)
     92                 add(i, j, 1);
     93     }
     94     for(int i = 1; i<=vN; i++)
     95         add(i, N+1, m);
     96 
     97     int maxflow = sap(0, N+1, N+2);
     98     return maxflow == uN;
     99 }
    100 
    101 void Flyod()
    102 {
    103     for(int k = 1; k<=N; k++)
    104         for(int i = 1; i<=N; i++)
    105             for(int j = 1; j<=N; j++)
    106                 maze[i][j] = min(maze[i][j], maze[i][k]+maze[k][j]);
    107 }
    108 
    109 int main()
    110 {
    111     while(scanf("%d%d%d", &vN, &uN, &m)!=EOF)
    112     {
    113         N = uN + vN;
    114         for(int i = 1; i<=N; i++)
    115         for(int j = 1; j<=N; j++)
    116         {
    117             scanf("%d", &maze[i][j]);
    118             if(maze[i][j]==0) maze[i][j] = INF/2;
    119         }
    120 
    121         Flyod();
    122         int l = 1, r = 200*400;
    123         while(l<=r)
    124         {
    125             int mid = (l+r)>>1;
    126             if(test(mid))
    127                 r = mid - 1;
    128             else
    129                 l = mid + 1;
    130         }
    131         printf("%d
    ", l);
    132     }
    133 }
    View Code
  • 相关阅读:
    6.让代码更具可读性
    5构造函数和析构函数
    4面向对象之类的继承
    3隐形的指针
    2面向对象之类的封装
    od快捷键
    1.纠结的c++
    101宏定义的其他用法
    100解剖宏定义函数
    99,printf scanf手动功能实现
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7821843.html
Copyright © 2020-2023  润新知