加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ PKU 2112 最大流

(2010-08-09 10:51:23)
标签:

poj

pku

2112

最大流

it

分类: 网络流

题目描述:

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

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

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

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

解题报告:

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

建图过程:

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

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

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

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

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

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

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define size 240
#define Max 0x7fffffff
int cap[size][size],s,t,n;
int queue[size],head,tail, Flow,prev[size];
bool findload()      //bfs找增广路径
{
 int i, tmp;
 memset(prev,-1,sizeof(prev));
 head = tail = 0;;
 queue[tail++] = s;
 prev[s] = s;
 while(head < tail)
 {
  tmp = queue[head++];
  for(i = 0; i < n; i++)
   if(prev[i] == -1 && cap[tmp][i] > 0)
   {
    prev[i] = tmp;
    if (i == t) return true;
    queue[tail++] = i;
   }
 }
 return false;
}
int maxflow()
{
    Flow = 0;
 while(findload())
 {
  int min = Max;
  for(int i = t; i != s; i = prev[i])  //增广路径中的最小可通过流
   if(min > cap[prev[i]][i])
    min = cap[prev[i]][i];
  for(int i = t; i != s; i = prev[i])//调整路径上的流
  {
   cap[prev[i]][i] -= min;
   cap[i][prev[i]] += min;
  }
  Flow += min;   //最大流累加
 }
 return Flow;
}
int k, c, m, x[size][size], ans;
void jeogia()
{
    int l = 0, r = ans;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        memset(cap, 0, sizeof(cap));
        s = 0, t = c + 1, n = c + 2;
        for(int i = 1; i <= k; i++) cap[s][i] = m;
        for(int i = k + 1; i <= c; i++) cap[i][t] = 1;
        for(int i = 1; i <= k; i++)
            for(int j = k + 1; j <= c; j++)
                cap[i][j] = (x[i][j] != 0 && x[i][j] <= mid);
        int tmp = maxflow();
        if (tmp == c - k)
        {
            if(mid < ans) ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
}
int main()
{
    while(scanf("%d%d%d", &k, &c, &m) != EOF)
    {
        c += k;
        for(int i = 1; i <= c; i++)
            for(int j = 1; j <= c; j++)
                scanf("%d", &x[i][j]);
        for(int k = 1; k <= c; k++)
            for(int i = 1; i <= c; i++)
                for(int j = 1; j <= c; j++)
                    if (x[i][k] && x[k][j] && (x[i][j] == 0 || x[i][k] + x[k][j] < x[i][j]))
                        x[i][j] = x[i][k] + x[k][j];
        ans = 200 * c;
        jeogia();
        printf("%d\n", ans);
    }
    return 0;
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有