Problem:
有k个机器和c头奶牛,一个机器最多可以供应m个奶牛使用,给定奶牛和机器之间的路径(图),问走的最远的奶牛走的路最短有多远?
Solution:
这道题难在不知道是网络流的题目,首先需要转换模型,设立一个超级起点向每一个奶牛的容量设置为1,然后超级汇点,每一个机器向汇点容量为m,题意就变成了在最大流是c的情况下距离如何最短?此时我们利用二分搜索,找到满足最大流是c的情况下的最逼近的距离。利用dinic网络流即可实现。
note:
1. 算法模板的效率一定要高,这样才能保证上层封装的效率,利用bfs模拟的dinic明显不如现在的直接dfs效率高。
2. 要对模型有一定的敏感性。
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<ctime>
#include<vector>
#include<fstream>
#include<list>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s,0,sizeof(s))
const double PI = 3.141592653589;
const int INF = 0x3fffffff;
int G[240][240];
int k, c, m;
int n;
void floyd(){
for(int k = 1; k <= n; ++k)
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
G[i][j] = min(G[i][j], G[i][k]+G[k][j]);
}
const int maxn = 240;
int cap[maxn][maxn];
int layer[maxn];
bool visited[maxn];
int st, en;//start point, end point
bool count_layer() {
queue<int> q; q.push(st);
memset(layer, -1, sizeof(layer));
layer[st] = 0;
while(!q.empty()) {
int v = q.front(); q.pop();
for(int i = st; i <= en; i++) {
if(layer[i] == -1 && cap[v][i] > 0) {
layer[i] = layer[v]+1;
if(i == en)
return true;
q.push(i);
}
}
}
return false;
}
int dfs(int root, int cur_flow) {
int dt = cur_flow;//the rest of cur_flow
if (root == en) return dt;
for (int i = 0; i <= en; i++) {
if (cap[root][i] > 0 && layer[i] == layer[root]+1) {
int flow = dfs(i, min(dt, cap[root][i]));
cap[root][i] -= flow;
cap[i][root] += flow;
dt -= flow;
}
}
return cur_flow - dt;
}
int dinic() {
int ans = 0;
while(count_layer())
ans += dfs(st, INF);
return ans;
}
void reG(int w) {
ms(cap);
for(int i = k+1; i <= k+c; i++) {
for(int j = 1; j <= k; j++) {
cap[i][j] = (G[i][j] <= w) ? 1 : 0;
}
}
for(int i = k+1; i <= k+c; i++)
cap[0][i] = 1;
for(int i = 1; i <= k; i++)
cap[i][n+1] = m;
}
int main() {
// freopen("/Users/really/Documents/code/input","r",stdin);
// freopen("/Users/really/Documents/code/output","w",stdout);
ios::sync_with_stdio(false);
cin >> k >> c >> m;
n = k + c;
en = n+1;
st = 0;
int w;
for(int i = 1; i <= k+c; i++) {
for(int j = 1; j <= k+c; j++) {
cin >> w;
G[i][j] = (w==0) ? INF : w;
}
}
floyd();
int l = 1, r = 40000;
int mid;
while(l < r) {
mid = (l+r)/2;
reG(mid);
int t = dinic();
if(t == c)
r = mid;
else
l = mid+1;
}
cout << l << endl;
return 0;
}