zoukankan      html  css  js  c++  java
  • POJ2112 Optimal Milking---二分+Floyd+网络流

    题目链接:

    https://vjudge.net/problem/POJ-2112

    题目大意:

    k个机器,每个机器最多服务m头牛。

    c头牛,每个牛需要1台机器来服务。

    告诉你牛与机器每个之间的直接距离。

    问:让所有的牛都被服务的情况下,使走的最远的牛的距离最短,求这个距离。

    解题思路:

    二分枚举距离,实际距离满足当前枚举距离限制的可以加入这条边。枚举的距离中符合条件的最小值就是答案。

    建图过程:

    一个超级汇点,每个机器和汇点的容量都是m。

    一个超级源点,和每头牛的容量都是1.

    机器i与牛j之间的距离如果小于等于当前枚举值mid,连接i,j,容量1.

    这样最大流的意义就是能够服务的牛最多是多少,如果最大流等于牛的总数c,表示当前枚举值mid符合条件,同时说明mid值还可能可以更小,更新二分右边界r = mid .(最终答案也是r不是mid)

    如果小于牛的总数,说明mid偏小,更新二分左边界,l = mid + 1.

    机器与牛之间的最短距离可以用floyd预处理出来。

      1 #include<iostream>
      2 #include<vector>
      3 #include<cstring>
      4 #include<queue>
      5 using namespace std;
      6 const int maxn = 300 + 10;
      7 const int INF = 0x3f3f3f3f;
      8 struct edge
      9 {
     10     int u, v, c, f;
     11     edge(int u, int v, int c, int f):u(u), v(v), c(c), f(f){}
     12 };
     13 vector<edge>e;
     14 vector<int>G[maxn];
     15 int a[maxn], p[maxn];
     16 void init(int n)
     17 {
     18     e.clear();
     19     for(int i = 0; i <= n; i++)G[i].clear();
     20 }
     21 void addedge(int u, int v, int c)
     22 {
     23     //cout<<u<<" "<<v<<" "<<c<<endl;
     24     e.push_back(edge(u, v, c, 0));
     25     e.push_back(edge(v, u, 0, 0));
     26     int m = e.size();
     27     G[u].push_back(m - 2);
     28     G[v].push_back(m - 1);
     29 }
     30 int Maxflow(int s, int t)
     31 {
     32     int flow = 0;
     33     for(;;)
     34     {
     35         memset(a, 0, sizeof(a));
     36         queue<int>q;
     37         q.push(s);
     38         a[s]  =INF;
     39         while(!q.empty())
     40         {
     41             int u = q.front();
     42             q.pop();
     43             for(int i = 0; i < G[u].size(); i++)
     44             {
     45                 edge& now = e[G[u][i]];
     46                 int v = now.v;
     47                 if(!a[v] && now.c > now.f)//还未流经并且边还有容量
     48                 {
     49                     p[v] = G[u][i];
     50                     a[v] = min(a[u], now.c - now.f);
     51                     q.push(v);
     52                 }
     53             }
     54             if(a[t])break;//已经到达汇点
     55         }
     56         if(!a[t])break;//已经没有增广路
     57         for(int u = t; u != s; u = e[p[u]].u)
     58         {
     59             e[p[u]].f += a[t];
     60             e[p[u] ^ 1].f -= a[t];
     61         }
     62         flow += a[t];
     63     }
     64     return flow;
     65 }
     66 int k, c, m, n;
     67 int s, t;
     68 int Map[maxn][maxn];
     69 void build_map(int Maxdist_min)
     70 {
     71     init(n);//每次构建容量网络清空边
     72     //超级源点s和所有牛建边,权值为1
     73     for(int i = k + 1; i <= n; i++)addedge(s, i, 1);
     74     //所有挤奶机和超级汇点建边,权值为m(也就是一台挤奶机可供牛的最大数目)
     75     for(int i = 1; i <= k; i++)addedge(i, t, m);
     76     for(int i = k + 1; i <= n; i++)//牛的编号,后c个
     77     {
     78         for(int j = 1; j <= k; j++)//挤奶机编号,前k个
     79         {
     80             if(Map[i][j] <= Maxdist_min)//小于最大距离,那么可以直达
     81                 addedge(i, j, 1);//牛和挤奶机可以配对
     82         }
     83     }
     84 }
     85 int main()
     86 {
     87     cin >> k >> c >> m;
     88     n = k + c;
     89     for(int i = 1; i <= n; i++)//前k个点为挤奶机,后c个点为牛
     90     {
     91         for(int j = 1; j <= n; j++)
     92         {
     93             cin >> Map[i][j];
     94             if(Map[i][j] == 0)Map[i][j] = INF;
     95         }
     96     }
     97     //Floyd求最短路
     98     for(int k = 1; k <= n; k++)
     99     {
    100         for(int i = 1; i <= n; i++)
    101         {
    102             for(int j = 1; j <= n; j++)
    103             {
    104                 Map[i][j] = min(Map[i][j], Map[i][k] + Map[k][j]);
    105             }
    106         }
    107     }
    108     int l = 0, r = 10000, mid;//此处最大距离不能是200,题目说的200只是一条边,可能要走很多条边
    109     s = 0, t = n + 1;
    110     while(l < r)
    111     {
    112         mid = (l + r) / 2;
    113         //cout<<mid<<endl;
    114         build_map(mid);
    115         if(Maxflow(s, t) >= c)//说明所有的牛已经到达,最大距离可以更小
    116             r = mid;
    117         else l = mid + 1;
    118     }
    119     cout<<r<<endl;//最大距离最小,这里的最大距离是r不是mid,因为最后一次循环的时候可能只更新mid和l,没有更新r
    120 }
  • 相关阅读:
    LOJ6433 [PKUSC2018] 最大前缀和 【状压DP】
    [NOIP2017] 宝藏 【树形DP】【状压DP】
    51Nod1824 染色游戏 【Lucas定理】【FMT】【位运算】
    51Nod1778 小Q的集合 【组合数】【Lucas定理】
    LOJ6436 [PKUSC2018] 神仙的游戏 【FFT】
    LOJ6432 [PKUSC2018] 真实排名 【组合数】
    BZOJ5210 最大连通子块和 【树链剖分】【堆】【动态DP】
    LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】
    洛谷3707 [SDOI2017] 相关分析 【线段树】
    RBAC
  • 原文地址:https://www.cnblogs.com/fzl194/p/8870772.html
Copyright © 2011-2022 走看看