hackerrank Cargo Delivery 费用流

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/KIDGIN7439/article/details/81002699