• POJ 2112 Optimal Milking (二分+最短路+最大流)


    <题目链接>

    题目大意:

      有K台挤奶机和C头奶牛,都被视为物体,这K+C个物体之间存在路径。给出一个 (K+C)x(K+C) 的矩阵A,A[i][j]表示物体i和物体j之间的距离,有些物体之间可能没有直接通路。 每台挤奶机可以容纳m头奶牛去挤奶,且每个奶牛仅可以去往一台挤奶机。现在安排这C头奶牛去挤奶,每头奶牛会去往某个挤奶机,求出这C头奶牛去其挤奶的最长路径的最小值。

    解题分析:
      因为要求最长路径的最小值,所以我们很容易想到二分答案。由于数据量较小,所以我们先用floyed求出所有点之间的最短距离,然后直接二分答案,枚举最长路径的最小值,再根据枚举的值建图,源点向所有机器连一条容量为m的边,所有的牛向汇点连一条容量为1的边,并且距离<=枚举值的机器与牛连一条容量为1的边,最后求最大流,如果最大流==c,则成立。

      1 #include <cstdio> 
      2 #include <cstring>
      3 #include <queue>
      4 #include <algorithm>
      5 #include <iostream>
      6 using namespace std;
      7 
      8 #define rep(i,s,t) for(int i=s;i<=t;i++)
      9 typedef long long LL;
     10 const int MX = 1050;
     11 const int MXE = 4 * MX * MX;
     12 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
     13 const int INF = 0x3f3f3f3f;
     14 int mp[250][250];
     15 int k, c, m,maxdist;
     16 struct MaxFlow {
     17     struct Edge {
     18         int v, nxt;
     19         LL w;
     20     } E[MXE];
     21     int tot, num, s, t;
     22     int head[MX];
     23     void init() {
     24         memset (head, -1, sizeof (head) );
     25         tot = 0;
     26     }
     27     void add (int u, int v, LL w) {
     28         E[tot].v=v,E[tot].nxt=head[u],E[tot].w=w;
     29         head[u] = tot++;
     30 
     31         E[tot].v=u,E[tot].nxt=head[v],E[tot].w=0;
     32         head[v] = tot++;
     33     }
     34     int  d[MX], vis[MX], gap[MX];
     35     void bfs() {
     36         memset (d, 0, sizeof (d) );
     37         memset (gap, 0, sizeof (gap) );
     38         memset (vis, 0, sizeof (vis) );
     39         queue<int>q;
     40         q.push (t);
     41         vis[t] = 1;
     42         while (!q.empty() ) {
     43             int u = q.front();
     44             q.pop();
     45             for (int i = head[u]; ~i; i = E[i].nxt) {
     46                 int v = E[i].v;
     47                 if (!vis[v]) {
     48                     d[v] = d[u] + 1;
     49                     gap[d[v]]++;
     50                     q.push (v);
     51                     vis[v] = 1;
     52                 }
     53             }
     54         }
     55     }
     56     int last[MX];
     57     LL dfs (int u, LL f) {
     58         if (u == t) return f;
     59         LL sap = 0;
     60         for (int i = last[u]; ~i; i = E[i].nxt) {
     61             int v = E[i].v;
     62             if (E[i].w > 0 && d[u] == d[v] + 1) {
     63                 last[u] = i;
     64                 LL tmp = dfs (v, min (f - sap, E[i].w) );
     65                 E[i].w -= tmp;
     66                 E[i ^ 1].w += tmp;
     67                 sap += tmp;
     68                 if (sap == f) return sap;
     69             }
     70         }
     71         if (d[s] >= num) return sap;
     72         if (! (--gap[d[u]]) ) d[s] = num;
     73         ++gap[++d[u]];
     74         last[u] = head[u];
     75         return sap;
     76     }
     77     LL solve (int st, int ed, int n) {
     78         LL flow = 0;
     79         num = n;s = st;t = ed;
     80         bfs();
     81         memcpy (last, head, sizeof (head) );
     82         while (d[s] < num) flow += dfs (s, INFLL);
     83         return flow;
     84     }
     85 }Maxflow;
     86 
     87 int MaxFlow_check(int mid) {    //建图,跑最大流
     88     Maxflow.init();    //初始化
     89     for (int i = 1 ; i <= k ; i++) {
     90         Maxflow.add(0, i, m);     //源点与机器相连,容量为m
     91         for (int j = k + 1 ; j <= k + c ; j++ )
     92             if (mp[i][j] <= mid) Maxflow.add(i, j, 1);     //机器与牛相连,容量为1
     93     }
     94     for (int i = k + 1 ; i <= k + c ; i++)
     95         Maxflow.add(i, k + c + 1, 1);      //牛与汇点相连,容量为1
     96     if ((int)(Maxflow.solve( 0, k + c + 1, k + c + 2)) == c) return 1;
     97     return 0;
     98 }
     99 void Floyed(int n){
    100     rep(k,1,n) rep(i,1,n) rep(j,1,n){
    101         mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
    102         maxdist=max(maxdist,mp[i][j]);     //找到最大的mp[i][j],为寻找二分的上界
    103     }
    104 }
    105 int main() {
    106     while(~scanf("%d%d%d", &k, &c, &m)) {
    107         for (int i = 1 ; i <= k + c ; i++)
    108             for (int j = 1 ; j <= k + c ; j++) {
    109                 scanf("%d", &mp[i][j]);
    110                 if (i != j && !mp[i][j]) mp[i][j] = INF;    //将0置为不可达
    111             }
    112         maxdist=-INF;Floyed(k+c);
    113         int l = 0, r = maxdist ,ans = 0;
    114         while(l <= r) {
    115             int mid = (l + r) >> 1;
    116             if (MaxFlow_check(mid))ans = mid,r = mid - 1;
    117             else l = mid + 1;
    118         }
    119         printf("%d
    ", ans);
    120     }
    121     return 0;
    122 }

    2018-11-24

  • 相关阅读:
    django with mysql (part-4)
    django with mysql (part-3)
    django with mysql (part-2)
    [LeetCode] 22. 括号生成(回溯/DP)
    [算法]求满足要求的进制(辗转相除(欧几里得算法),求最大公约数gcd)
    [算法]体积不小于V的情况下的最小价值(0-1背包)
    [LeetCode]96. 不同的二叉搜索树(DP,卡特兰数)
    [LeetCode]98. 验证二叉搜索树
    [LeetCode]21. 合并两个有序链表(递归)
    [LeetCode]538. 把二叉搜索树转换为累加树
  • 原文地址:https://www.cnblogs.com/00isok/p/10012691.html
Copyright © 2020-2023  润新知