• POJ2112 最大流(Isap+Floyd+二分)


    题意:有K个挤奶器,C头奶牛,每个挤奶器最多能给M头奶牛挤奶。求使C头奶牛头奶牛需要走的路程的最大路程最小。

    (1)首先跑一遍Floyd,求出任意两个点的最短距离

    (2)然后进行二分,对奶牛和挤奶器距离<=mid的建边,权值为1

    (3)判断是否C头奶牛都可以有挤奶器挤奶,(最大流是否等于C)

    (4)然后一直二分求最小的

    (5)要注意的地方,代码有注释

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <algorithm>
      6 using namespace std;
      7 #define inf 0x7fffffff
      8 #define N 300
      9 #define M 40000
     10 int dis[N],gap[N],cur[N],pre[N];
     11 int size,head[N];
     12 int map[N][N];
     13 int num,k,c,m;
     14 int s,e,nv,mid;
     15 struct Edge {
     16     int v,w,next;
     17     Edge() {}
     18     Edge(int V,int W,int NEXT):v(V),w(W),next(NEXT) {}
     19 } edge[M];
     20 void InsertEdge(int u,int v,int w) { // 加边 
     21     edge[size] = Edge(v,w,head[u]);
     22     head[u] = size++;
     23     edge[size] = Edge(u,0,head[v]);
     24     head[v] = size++;
     25 }
     26 int Isap(int st,int ed,int n) { //Isap模板 
     27     for(int i=0; i<=n; i++) {
     28         cur[i] = head[i];
     29         gap[i] = dis[i] = 0;
     30     }
     31     int u = pre[st] = st;
     32     int aug = inf ,maxflow = 0;
     33     while(dis[st] < n) {
     34 loop:
     35         for(int &i=cur[u]; i!=-1; i=edge[i].next) {
     36             int v = edge[i].v;
     37             if(edge[i].w && dis[u] == dis[v] + 1) {
     38                 aug = min(aug,edge[i].w);
     39                 pre[v] = u;
     40                 u = v;
     41                 if(v==ed) {
     42                     maxflow += aug;
     43                     for(u=pre[u]; v!=st; v=u,u=pre[u]) {
     44                         edge[cur[u]].w -= aug;
     45                         edge[cur[ u]^1].w += aug;
     46                     }
     47                     aug = inf;
     48                 }
     49                 goto loop;
     50             }
     51         }
     52         int mindis = n;
     53         for(int i=head[u]; i!=-1; i=edge[i].next) {
     54             int v = edge[i].v;
     55             if(edge[i].w && dis[v]<mindis) {
     56                 cur[u] = i;
     57                 mindis = dis[v];
     58             }
     59         }
     60         if(--gap[dis[u]]==0) break;
     61         gap[dis[u] = mindis+1]++;
     62         u = pre[u];
     63     }
     64     return maxflow;
     65 }
     66 
     67 void Init() {    // 建图 
     68     memset(head,-1,sizeof(head));
     69     size = 0;
     70     for(int i=1; i<=k; i++) { //k个挤奶器 
     71         for(int j=k+1; j<=num; j++) { //c头奶牛 
     72             if(map[i][j]<=mid) InsertEdge(j,i,1); //如果奶牛到挤奶器的最短距离<=mid,建权值为1的边 
     73         }
     74     }
     75     for(int i=1; i<=k; i++) InsertEdge(i,e,m); //每个挤奶器最多可以挤k头牛 
     76     for(int i=k+1; i<=num; i++) InsertEdge(s,i,1); //建一条源点到奶牛的边,权值为1 
     77 
     78 }
     79 
     80 void Floyd() { //Floyd求两个点的最短距离 
     81     for(int pos=1; pos<=num; pos++) {
     82         for(int i=1; i<=num; i++) {
     83             if(pos==i||map[i][pos]==inf) continue;
     84             for(int j=1; j<=num; j++) {
     85                 if(pos==j||map[pos][j]==inf) continue;
     86                 if(map[i][j] > map[i][pos] + map[pos][j])
     87                     map[i][j] = map[i][pos] + map[pos][j];
     88             }
     89         }
     90     }
     91 }
     92 
     93 int main() {
     94     while(scanf("%d%d%d",&k,&c,&m)!=EOF) {
     95         num = k+c; //矩阵的规格 
     96         s = 0 ; //源点 
     97         e = num+1; //汇点 
     98         nv = e+1; //结点总数 
     99         for(int i=1; i<=num; i++) {
    100             for(int j=1; j<=num; j++) {
    101                 scanf("%d",&map[i][j]);
    102                 if(i!=j && !map[i][j]) //除了i==j,map[i][j]==0,map[i][j]=inf;
    103                     map[i][j] = inf;
    104             }
    105         }
    106         Floyd();
    107         int l = 0 , r = 40000;
    108         while(l<=r) {
    109             mid=l+(r-l)/2; //有时候l+r可以超了。。 
    110             Init();
    111             if(Isap(s,e,nv)==c) r = mid-1; //如果所有的奶牛都可以找到相应的挤奶器 
    112             else l = mid+1;
    113         }
    114         printf("%d
    ",l);
    115     }
    116     return 0;
    117 }
    View Code
  • 相关阅读:
    WebBrowser无法显示招商银行password输入控件的问题
    对流式计算模型的理解
    Dev BarManager使用方法
    创业的需求分析——创业杂记【1】
    使用Apktools反编译apk应用
    【JUnit4.10源码分析】3.4 Description与測试树
    基于KWIC 的keyword匹配算法(管道+过滤器模式下实现)
    纯CSS滑动效果
    PhotoSwipe简介
    包加载失败的解决办法
  • 原文地址:https://www.cnblogs.com/ar940507/p/3264877.html
Copyright © 2020-2023  润新知