Description
Input
Output
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; }