zoukankan      html  css  js  c++  java
  • POJ-2112 Optimal Milking

    题目大意:

    有k个挤奶器,在牧场里有c头奶牛,每个挤奶器可以满足m个奶牛,奶牛和挤奶器都可以看成是实体,现在给出两个实体之间的距离,如果没有路径相连,则为0,现在问你在所有方案里面,这c头奶牛需要走的最大距离的最小值。

    解题思路:

    floyd+最大流+二分

    首先用floyd求出两个实体间的最短距离,然后二分枚举最大距离的最小值,用最大流来判断是否存在这个解。

    因为涉及Floyd所以INF设置的值最好不要太大。千万不能是0x7fffffff

    二分枚举答案的时候,r可以设置初值为1e4即可。

    在使用最大流判断是否存在解的时候,要对每个解都重新建图。

    建图需要一个超级源点,把所有的奶牛与源点相连,容量设置为1

    把所有的挤奶器与汇点相连,容量为m

    然后对于挤奶器和奶牛的距离不超过判断的解的距离的连边,容量设置为1

    然后求解即可。

    (建图部分可以直接看代码比较好)

    代码:

    #include <queue>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef struct node{
        int v, cap, nxt;
        node(int a = 0, int b = 0, int c = 0){
            v = a; cap = b; nxt = c;
        }
    }Edge;
    
    const int INF = 1e7;
    const int maxn = 300;
    const int maxm = 1e5;
    
    Edge edge[maxm];
    int t, tot, K, C, M, N;
    int head[maxm], dis[maxn], d[maxn][maxn];
    
    inline int Min(int a, int b){
        return (a < b ? a : b);
    }
    void floyd(){
        for(int k = 1; k <= N; ++k){
            for(int i = 1; i <= N; ++i){
                for(int j = 1; j <= N; ++j){
                    d[i][j] = Min(d[i][j], d[i][k] + d[k][j]);
                }
            }
        }
    }
    void add(int u, int v, int cap){
        edge[tot] = Edge(v, cap, head[u]);
        head[u] = tot++;
        edge[tot] = Edge(u, 0, head[v]);
        head[v] = tot++;
    }
    int bfs(){
        queue<int> q;
        while(!q.empty()) q.pop();
        memset(dis, 0, sizeof(dis));
        dis[0] = 1; q.push(0);
        while(!q.empty()) {
            int x = q.front(); q.pop();
            if(x == t) break;
            for(int i = head[x]; ~i; i = edge[i].nxt){
                Edge &e = edge[i];
                if(e.cap && dis[e.v] == 0){
                    dis[e.v] = dis[x] + 1;
                    q.push(e.v);
                }
            }
        }
        return dis[t];
    }
    int dfs(int x, int f){
        if(x == t) return f;
        int sum = 0;
        for(int i = head[x]; ~i; i = edge[i].nxt){
            Edge &e = edge[i];
            if(e.cap && dis[e.v] == dis[x] + 1){
                int ret = dfs(e.v, Min(e.cap, f));
                sum += ret; f -= ret;
                e.cap -= ret; edge[i^1].cap += ret;
            }
        }
        return sum;
    }
    void buildGraph(int lev){
        tot = 0;
        memset(head, -1, sizeof(head));
        for(int i = K + 1; i <= N; ++i) add(0, i, 1);
        for(int i = 1; i <= K; ++i) add(i, t, M);
        for(int i = K + 1; i <= N; ++i){
            for(int j = 1; j <= K; ++j){
                if(d[i][j] <= lev) add(i, j, 1);
            }
        }
    }
    bool dinic(){
        int ret = 0;
        while(bfs()) ret += dfs(0, INF);
        return (ret >= C);
    }
    int main(){
        while(~scanf("%d%d%d", &K, &C, &M)){
            N = K + C; t = N + 1;
            for(int i = 1; i <= N; ++i)
                for(int j = 1; j <= N; ++j){
                    scanf("%d", &d[i][j]);
                    if(d[i][j] == 0) d[i][j] = INF;
                }
            floyd();
            int l = 0, r = 1e4, ans, mid;
            while(l < r){
                mid = (l + r) >> 1;
                buildGraph(mid);
                if(dinic()) {
                    ans = mid; r = mid;
                }else l = mid + 1;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }


  • 相关阅读:
    swift 中 Self 与self
    Swift 中的泛型
    mac 报文件已损坏 怎么办
    winxp秘钥
    字符串拷贝函数strcpy, strcat, sprintf, strncpy, strncat和snprintf的区别
    【原创】Linux应用程序完整调用自己写的字符设备驱动过程
    idea中新建git分支,并提交到远程github
    (JS-PHP)使用RSA算法进行加密通讯
    Linux日志相关的命令
    hibernate中关于is null的查询
  • 原文地址:https://www.cnblogs.com/wiklvrain/p/8179400.html
Copyright © 2011-2022 走看看