Optimal Milking(二分图多重匹配+二分)(网络流)

Optimal Milking
Time Limit:2000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u
Submit  Status  Practice  POJ 2112

Description

FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) cows. A set of paths of various lengths runs among the cows and the milking machines. The milking machine locations are named by ID numbers 1..K; the cow locations are named by ID numbers K+1..K+C. 

Each milking point can "process" at most M (1 <= M <= 15) cows each day. 

Write a program to find an assignment for each cow to some milking machine so that the distance the furthest-walking cow travels is minimized (and, of course, the milking machines are not overutilized). At least one legal assignment is possible for all input data sets. Cows can traverse several paths on the way to their milking machine. 

Input

* Line 1: A single line with three space-separated integers: K, C, and M. 

* Lines 2.. ...: Each of these K+C lines of K+C space-separated integers describes the distances between pairs of various entities. The input forms a symmetric matrix. Line 2 tells the distances from milking machine 1 to each of the other entities; line 3 tells the distances from machine 2 to each of the other entities, and so on. Distances of entities directly connected by a path are positive integers no larger than 200. Entities not directly connected by a path have a distance of 0. The distance from an entity to itself (i.e., all numbers on the diagonal) is also given as 0. To keep the input lines of reasonable length, when K+C > 15, a row is broken into successive lines of 15 numbers and a potentially shorter line to finish up a row. Each new row begins on its own line. 

Output

A single line with a single integer that is the minimum possible total distance for the furthest walking cow. 

Sample Input

2 3 2
0 3 2 1 1
3 0 3 2 0
2 3 0 1 0
1 2 1 0 2
1 0 0 2 0

Sample Output

2


题意:K个产奶机,C头奶牛,每个产奶机最多可供M头奶牛使用;并告诉了产奶机、奶牛之间的两两距离Dij(0<=i,j<K+C)。

问题:如何安排使得在任何一头奶牛都有自己产奶机的条件下,奶牛到产奶机的最远距离最短?最短是多少?

解:问最远距离最小是肯定是二分查找啦,二分距离,二分图多重匹配判断能否满流;


使用二分图多重匹配+二分方式

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
const int maxn=300,inf=0x3f3f3f3f,M=300,N=300;
int mp[maxn][maxn],map[maxn][maxn];
int vlink[M],link[M][N];
bool vis[M];
int k,c,w;

int path(int s)
{
    for(int i=0;i<k;i++)///挤奶器集合
    {
        if(map[s][i] && !vis[i])
        {
            vis[i]=true;
            if(vlink[i]<w)///机器可用上限
            {
                link[i][vlink[i]++]=s;
                return 1;
            }
            for(int j=0;j<vlink[i];j++)
            {
                if(path(link[i][j]))
                {
                    link[i][j]=s;
                    return 1;
                }
            }
        }
    }
    return 0;
}
bool max_match()
{
    int ans=0;
    memset(vlink,0,sizeof(vlink));
    for(int i=0;i<c;i++)///奶牛集合
    {
        memset(vis,false,sizeof(vis));
        if(!path(i))
        return false;
    }
    return true ;///所有奶牛都有一个挤奶器返回真
}


int main()
{
    while(~scanf("%d%d%d",&k,&c,&w))
    {
        for(int i=0;i<c+k;i++)
        {
            for(int j=0;j<k+c;j++)
            {
                scanf("%d",&mp[i][j]);
                if(mp[i][j]==0)///这里一定要修改,不然会影响floyd算法,
                    mp[i][j]=inf;
            }
        }
        ///floyd必须求
        for(int i=0;i<k+c;i++)
        {
            for(int j=0;j<k+c;j++)
            {
                for(int l=0;l<k+c;l++)
                {
                    if(mp[j][l]>mp[j][i]+mp[i][l])
                        mp[j][l]=mp[j][i]+mp[i][l];
                }
            }
        }
        int l=0,r=inf,mid;
        while(l<r)
        {
            mid=(l+r)/2;
            memset(map,0,sizeof(map));
            for(int i=k;i<c+k;i++)///奶牛->机器
            {
               for(int j=0;j<k;j++)
               {
                  if(mp[i][j]<=mid)///二分查找最短距离
                    map[i-k][j]=1;
               }
            }
            if(max_match())///二分图多重匹配,奶牛都有机器用时减小上线
                r=mid;
            else
                l=mid+1;
        }
        cout<<r<<endl;

    }
    return 0;
}


网络流+二分(两种方式大同小异)

题目描述:
农场主John将他的K(1≤K≤30)个挤奶器运到牧场,在那里有C(1≤C≤200)头奶牛,在奶
牛和挤奶器之间有一组不同长度的路。K个挤奶器的位置用1~K的编号标明,奶牛的位置用K+1~
K+C的编号标明。
每台挤奶器每天最多能为M(1≤M≤15)头奶牛挤奶。
编写程序,寻找一个方案,安排每头奶牛到某个挤奶器挤奶,并使得C头奶牛需要走的所有
路程中的最大路程最小。每个测试数据中至少有一个安排方案。每条奶牛到挤奶器有多条路。
// 本题的求解算法:先用Floyd算法求出能达到的任意两点之间的最短路径,然后用Dinic算法
// 求最大流;搜索最大距离的最小值采用二分法进行。

// 建图问题 : 给个源点 s 。源点到奶牛的流量为1 如果奶牛到达挤奶器距离在max_min范围内 那没就然 该奶牛到该挤奶器的流量为1
// 再给个汇点  那么挤奶器到汇点的流量就是M 正好符合限制 
/// 然后二分查找 max_min就可以了
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <string.h>
using namespace std;
#define MOD 1000000007
#define INF 1000000000
#define maxn 310
#define maxm 48010
#define LL  __int64//long long
int M,K,C,N;
int cap[maxn][maxn],flow[maxn][maxn];
int dis[maxn][maxn];//,bl[1100];
void build(int max_min){  // 建图
    int i,j;
    memset(cap,0,sizeof(cap));
    memset(flow,0,sizeof(flow));
   for(i=1;i<=K;i++) cap[i][N+1]=M;
   for(i=K+1;i<=N;i++) cap[0][i]=1;
   for(i=K+1;i<=N;i++)
    for(j=1;j<=K;j++)
     if(dis[i][j]<=max_min) cap[i][j]=1;
}
int level[maxn];
bool BFS(int s,int t){
   memset(level,0,sizeof(level));
   queue<int> Q;
   int u;
   int i;
   Q.push(s);
   level[s]=1;
   while(!Q.empty()){
      u=Q.front();
      Q.pop();
      if(u==t) return true;
      for(i=1;i<=t;i++)
        if(!level[i]&&cap[u][i]>flow[u][i])
        {
            level[i]=level[u]+1;
            Q.push(i);
        }
   }
   return false;
}
int dfs(int u,int maxf,int t){
    if(u==t||maxf==0) return maxf;
    int ret=0,f,i;
    for(i=1;i<=t;i++)
      if(cap[u][i]>flow[u][i]&&level[u]+1==level[i]){
           f= dfs(i,min(maxf,cap[u][i]-flow[u][i]),t);
           flow[u][i]+=f;
           flow[i][u]-=f;
           maxf-=f;
           ret+=f;
           if(maxf==0) break;
    }
    return ret;
}
int Dinic(int s,int t){
   int flow=0;
   while(BFS(s,t)){
    flow+=dfs(s,INF,t);
   }
   return flow;
}
void init(){
   // memset(cap,0,sizeof(cap));
  //  memset(flow,0,sizeof(flow));
}
int main(){
    int i,j,k;
   while(scanf("%d %d %d",&K,&C,&M)!=EOF){

    N=K+C;
    for(i=1;i<=N;i++)
       for(j=1;j<=N;j++){
        scanf("%d",&dis[i][j]);
        if(dis[i][j]==0) dis[i][j]=INF;
    }
    for(k=1;k<=N;k++)
       for(i=1;i<=N;i++)
         for(j=1;j<=N;j++)
            if(dis[i][j]>dis[i][k]+dis[k][j])
              dis[i][j]=dis[i][k]+dis[k][j];
    /* for(i=0;i<=N+1;i++,printf("\n"))
        for(k=0;k<=N+1;k++)
         printf("%d ",cap[i][k]);*/
      int L=0,R=100000,mid;
      int tp;
      while(L<R){// 二分枚举 max_min
         mid=(L+R)>>1;
         build(mid);
         tp=Dinic(0,N+1);
         if(tp>=C) R=mid;
         else L=mid+1;
      }
     printf("%d\n",R);
   }

   return 0;
}







你可能感兴趣的:(Optimal Milking(二分图多重匹配+二分)(网络流))