题目链接:https://www.hackerrank.com/contests/w38/challenges/cargo-delivery
题目大意:一个无向图,有 k 辆车要依次从 0 到 n-1。一开始每条边权重为 0,每经过一次车该边权重 +1。有 t 次机会使一条边边权 -1。现求无向图中最大的边权重最小化是多少。
费用流,二分最优值x,两个点之间连两条边,一条边容量为二分的值x,费用为0,另一个容量为inf,费用为1,源点到0的容量为k,跑最小费用最大流,看费用是否小于t。
#include <bits/stdc++.h>
using namespace std;
vector<string> split_string(string);
const int N = 2010;
const int M = 100010;
const int inf = 100100100;
struct Edge
{
int s, t, f, c;
int next;
}e[M];
int cnt;
int sumFlow;
int pre[N], dist[N], eat[N];
int inq[N], vt[N];
void init()
{
cnt = 0;
memset(pre, -1, sizeof(pre));
}
void addedge(int s, int t, int f, int c)
{
e[cnt].s = s, e[cnt].t = t, e[cnt].f = f, e[cnt].c = c, e[cnt].next = pre[s];
pre[s] = cnt++;
e[cnt].s = t, e[cnt].t = s, e[cnt].f = 0, e[cnt].c = -c, e[cnt].next = pre[t];
pre[t] = cnt++;
}
bool SPFA(int s, int t, int n)
{
queue <int> q;
memset(inq, 0, sizeof(inq));
memset(eat, -1, sizeof(eat));
memset(vt, 0 ,sizeof(vt));
for(int i = 0; i <= n; i ++) dist[i] = inf;
inq[s] = 1;
vt[s]++;
dist[s] = 0;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
inq[u] = 0;
if(vt[u] > n) break;
for(int i = pre[u]; i != -1; i = e[i].next){
int v = e[i].t;
if(e[i].f && dist[v] > dist[u] + e[i].c){
dist[v] = dist[u] + e[i].c;
eat[v] = i;
if(!inq[v]){
q.push(v);
vt[v]++;
inq[v] = 1;
}
}
}
}
if(dist[t] == inf || !q.empty()) return false;
return true;
}
int MCMF(int s, int t, int n) // minCostMaxFlow
{
int flow = 0; //
int i, minflow, mincost;
mincost = 0;
while(SPFA(s, t, n)){
minflow = inf + 1;
for(i = eat[t]; i != -1; i = eat[e[i].s])
if(e[i].f < minflow) minflow = e[i].f;
flow += minflow;
for(i = eat[t]; i != -1; i = eat[e[i].s]){
e[i].f -= minflow;
e[i^1].f += minflow;
}
mincost += dist[t] * minflow; //
}
sumFlow = flow; //
return mincost;
}
// Complete the minimumBrokenness function below.
int minimumBrokenness(int n, int m, int k, int t) {
// Return the minimum possible brokenness of a truck among all k trucks driving from city 0 to city n-1. Take the information about roads from standard input.
vector<int> u(m), v(m);
for (int i = 0; i < m; ++ i) {
cin >> u[i] >> v[i];
}
int lb = 0, ub = k;
while (ub - lb > 1) {
int mid = lb + ub >> 1;
// MCMF bar;
init();
for (int i = 0; i < m; ++ i) {
addedge(u[i], v[i], mid, 0);
addedge(v[i], u[i], mid, 0);
addedge(u[i], v[i], t, 1);
addedge(v[i], u[i], t, 1);
}
addedge(n, 0, k, 0);
int cost = MCMF(n, n - 1, n);
if (sumFlow < k || (sumFlow == k && cost > t)) lb = mid;
else ub = mid;
//cerr << ub << endl;
}
return ub - 1;
}