题意:
K个产奶机,C头奶牛,每个产奶机最多可供M头奶牛使用;并告诉了产奶机、奶牛之间的两两距离Dij(0<=i,j<K+C)。如何安排使得在任何一头奶牛都有自己产奶机的条件下,奶牛到产奶机的最远距离最短?最短是多少?
思路:
二分答案,这里可以用二分图的多重匹配判断,也可以建图跑网络流。
二分 + 多重匹配
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn = 3e2 + 5;
const int inf = (1 << 29);
struct node{
int len, mul[20];
} match[maxn];
int mp[maxn][maxn];
bool vis[maxn];
int k, c, m;
bool dfs(int u, int mid){
for(int i = 1; i <= k; i++){
int v = i;
if(vis[v] || mp[u][v] == inf || mp[u][v] > mid) continue;
vis[v] = true;
if(match[v].len < m){
match[v].mul[match[v].len++] = u;
return true;
}
else {
for(int j = 0; j < match[v].len; j++){
if(dfs(match[v].mul[j], mid)) {
match[v].mul[j] = u;
return true;
}
}
}
}
return false;
}
bool solve(int mid){
for(int i = 1; i <= k; i++) match[i].len = 0;
for(int i = k + 1; i <= k + c; i++){
for(int j = 1; j <= k; j++) vis[j] = false;
if(!dfs(i, mid)) return false;
}
return true;
}
int main(){
while(~scanf("%d%d%d", &k, &c, &m)){
for(int i = 1; i <= k + c; i++)
for(int j = 1; j <= k + c; j++) {
scanf("%d", &mp[i][j]);
if(mp[i][j] == 0 && i != j) mp[i][j] = inf;
}
for(int p = 1; p <= k + c; p++)
for(int i = 1; i <= k + c; i++)
for(int j = 1; j <= k + c; j++)
mp[i][j] = min(mp[i][j], mp[i][p] + mp[p][j]);
int l = 0, r = 46000;
while(l < r) {
int mid = (l + r) / 2;
if(solve(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", l);
}
}
二分 + 网络流
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<cstdlib>
#include<map>
#include<set>
using namespace std;
#define CL(x,v) memset(x,v,sizeof(x));
#define R(i,st,en) for(int i=st;i<en;++i)
#define LL long long
#define inf 0x3f3f3f3f
int a[240][240];
int K,C,M;
const int maxn = 240;
int cap[maxn][maxn];
int lev[maxn];
int n, m;
int st, en;
bool bfs()
{
queue <int> q;
while (!q.empty()) q.pop();
memset(lev, -1, sizeof(lev));
lev[st] = 0;
q.push(st);
while (!q.empty())
{
int u = q.front();q.pop();
for (int v = 0; v <= n+1; ++v)
if (lev[v] == -1 && cap[u][v] != 0)
{
lev[v] = lev[u] + 1;
q.push(v);
}
}
return lev[en] != -1;
}
int dfs(int u, int cur_flow)
{
int dt = cur_flow;
if (u == en) return dt;
for (int v = 0; v <= n + 1; ++v)
{
if (cap[u][v] > 0 && lev[u] + 1 == lev[v])
{
int flow = dfs(v, min(dt, cap[u][v]));
cap[u][v] -= flow;
cap[v][u] += flow;
dt -= flow;
}
}
return cur_flow - dt;
}
int dinic()
{
int cur_flow, ans = 0;
while(bfs())
while(cur_flow = dfs(st, inf))
ans += cur_flow;
return ans;
}
void build(int dis) //建图
{
memset(cap, 0, sizeof(cap));
n = K + C;
st = 0;
en = n + 1;
for (int i = 1; i <= K; ++i)
cap[0][i] += M;
for (int i = K + 1; i <= K + C; ++i)
cap[i][en] += 1;
for (int i = 1; i <= K; ++i)
for (int j = K + 1; j <= K + C; ++j)
if (a[i][j] <= dis)
cap[i][j] += 1;
}
int main()
{
while(~scanf("%d%d%d",&K, &C, &M))
{
for (int i = 1; i <= K + C; ++i)
for (int j = 1; j <= K + C; ++j)
{
scanf("%d", &a[i][j]);
if (a[i][j] == 0) a[i][j] = inf;
}
for (int k = 1; k <= K + C; ++k)
for (int i = 1; i <= K + C; ++i)
for (int j = 1; j <= K + C; ++j)
a[i][j]= min(a[i][j],a[i][k]+a[k][j]);
/*for (int i = 1; i <= K + C; ++i)
{
for (int j = 1; j <= K + C; ++j)
cout<<a[i][j]<<" ";
cout<<endl;
}*/
int ans = 1, low = 1, high = inf;
while(low <= high)
{
int mid = (low + high) >> 1;
build(mid);
if (dinic() == C)
{
ans = mid;
high = mid - 1;
}
else
low = mid + 1;
}
printf("%d\n", ans);
}
return 0;
}