poj 2112 Optimal Milking(floyd+…

题意:有K台挤奶机、C头奶牛,以及他们之间距离,每只奶牛都要走到任意一台机器中,每台机器最多为M只奶牛服务,问所有奶牛都完成任务,所走的路程最远的那只奶牛,所走的路程最短可以是多少。

思路:floyd + 二分+ 最大流。
很容易想到最大流 建立一个超级源点和汇点把挤奶机和汇点连起来 容量为M ,奶牛与源点连起来 容量为1
先floyd求出每两个实体间的最小距离 然后二分找出最大

//788K      454MS
#include <stdio.h>
#include <string.h>
#define Max 300
#define inf 0x3f3f3f3f;
int dist[Max][Max],mat[Max][Max],pre[Max];
int K,C,M,src,des;

void Build (int num)          //建图
{
      memset (mat,0,sizeof(mat));
      for (int i = 1+K; i <= des-1; i ++)  //在当前路径下能走一路线
              for (int j = 1; j <= K; j ++)
                      if (dist[i][j] <= num)
                              mat[i][j] = 1;
      for (int i = 1; i <= K; i ++)  //与汇点相边
              mat[i][des] = M;
      for (int i = 1+K; i <= des-1; i ++) //与源点相连
              mat[src][i] = 1;
}

bool BFS ()
{
      memset (pre,0xff,sizeof(pre));
      int que[Max];
      int front = 0,rear = 0;
      pre[src] = 0;
      que[rear++] = src;
      while (front != rear)
      {
              int u = que[front++];
              front = front % Max;
              for (int v = 1; v <= des; v ++)
              {
                      if (pre[v] != -1||mat[u][v] == 0)
                              continue;
                      pre[v] = u;
                      if (v == des)
                              return true;
                      que[rear++] = v;
                      rear = rear % Max;
              }
      }
      return false;
}

int EK ()          //EK算法 每回增广的容量只能1
{
      int ans = 0,i;
      while (BFS())
      {
              ans += 1;
              for (i = des; i != src; i = pre[i])
              {
                      mat[pre[i]][i] -= 1;
                      mat[i][pre[i]] += 1;
              }
      }
      return ans;
}
int main ()
{
      int i,j,k;
      while (~scanf ("%d%d%d",&K,&C,&M))
      {
              src = 0,des = K + C + 1;
              for (i = 1; i <= K+C; i ++)
                      for (j = 1; j <= K+C; j ++)
                      {
                              scanf ("%d",&dist[i][j]);
                              if (dist[i][j] == 0)
                                      dist[i][j] = inf;
                      }

              for (k = 1; k <= des-1; k ++)  //floyd
                      for (i = 1; i <= des-1; i ++)
                              for (j = 1; j <= des-1; j ++)
                                      if (dist[i][j] > dist[i][k]+dist[k][j])
                                              dist[i][j] = dist[i][k]+dist[k][j];
              int l = 0,r = 10000;
              int ans = 0;
              int count = 0;
              while (l <= r)  //二分
              {
                      int mid = (l + r)>>1;
                      Build (mid);
                      int sum = EK();                //sum 表示有多少牛能走到挤奶机

                      if (sum == C)                  //表示 全部的牛都能走到
                      {
                              ans = mid;                //当前的距离符合
                              r = mid - 1;
                      }
                      else
                              l = mid + 1;
              }
              printf ("%d\n",ans);
      }
      return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值