2019 Multi-University Training Contest 1 1005(最短路+最小割

原文地址:http://nuoyanli.com/contest_hdu_multi-university-training-contest-1-1005/

1005 Path (HDU - 6582)

题意:

给你一个有向图,1到n的最短路可能有多条,需要你删去一些边使得1到n的最短路严格变长。
删掉边的费用为边的长度,求最小花费。

思路:

读懂题后,思考了一阵发现是以最小的代价破坏最短路,翻板子之后发现是最短路+最小割
首先将最短路的所有边存下来(最短路可能有多条),然后利用这些边建图,求新图的1到n的最小割。搞了好久,种于改好了板子,签到了!!!
最短路+最小割居然是签到题。当然榜有一点点歪,不过总体难度算是很难了。
ps:刘老师说先上辣椒水,再上老虎凳

代码:

#include 

#define endl "\n"
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll maxn = 1e4 + 5;

ll head[maxn], Header[maxn], vis[maxn], length[maxn], gap[maxn];
ll n, m, tot, step;

struct Node1 {
    ll to;
    ll cap;
    ll next;
} edge[4 * maxn];

struct Node2 {
    ll to, next;
    ll length;
} Edges[maxn];


// 记录每个点的最短距离
void spfa(ll s) {
    memset(vis, 0, sizeof(vis));
    memset(length, INF, sizeof(length));
    queue<ll> q;
    q.push(s);
    vis[s] = 1;
    length[s] = 0;
    while (!q.empty()) {
        ll u = q.front();
        q.pop();
        vis[u] = 0;
        for (ll i = Header[u]; i != -1; i = Edges[i].next) {
            ll v = Edges[i].to;
            if (length[v] > length[u] + Edges[i].length) {
                length[v] = length[u] + Edges[i].length;
                if (!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
}

struct Sap {
    void init() {
        memset(head, -1, sizeof(head));
        tot = 0;
    }

    void add(ll u, ll v, ll cap) {
        edge[tot].to = v, edge[tot].cap = cap, edge[tot].next = head[u], head[u] = tot++;
        edge[tot].to = u, edge[tot].cap = 0, edge[tot].next = head[v], head[v] = tot++;//反向边
    }

    ll DFS(ll u, ll s, ll t, ll num) {
        if (u == t) return num;
        ll v;
        ll f, minlength = step - 1, flow = 0;
        for (ll i = head[u]; i != -1; i = edge[i].next) {
            v = edge[i].to;
            if (edge[i].cap <= 0) continue;
            if (length[v] + 1 == length[u]) {
                f = DFS(v, s, t, min(edge[i].cap, num - flow));
                edge[i].cap -= f;
                edge[i ^ 1].cap += f;
                flow += f;
                if (flow == num) {
                    break;
                }
                if (length[s] >= step) return flow;
            }
            minlength = min(length[v], minlength);
        }
        if (flow == 0) {
            if (--gap[length[u]] == 0) {
                length[s] = step;
            }
            length[u] = minlength + 1;
            gap[length[u]]++;
        }
        return flow;
    }

    void create() {
        for (ll i = 1; i <= n; i++) {
            for (ll j = Header[i]; j != -1; j = Edges[j].next) {
                if (length[i] + Edges[j].length == length[Edges[j].to]) {
                    add(i, Edges[j].to, Edges[j].length);
                }
            }
        }
    }

    ll maxINFlow(ll s, ll t) {
        ll sum = 0;
        memset(length, 0, sizeof(length));
        memset(gap, 0, sizeof(gap));
        gap[0] = step;
        while (length[s] < step) {
            sum += DFS(s, s, t, INF);
        }
        return sum;
    }
} sap;

//邻接表存图
void Add(ll a, ll b, ll c) {
    Edges[step].next = Header[a];
    Edges[step].to = b;
    Edges[step].length = c;
    Header[a] = step++;
}

int main() {
    ios::sync_with_stdio(0);
    ll a, b, c;
    int t;
    cin >> t;
    while (t--) {
        memset(Header, -1, sizeof(Header));
        cin >> n >> m;
        step = 0;
        for (ll i = 0; i < m; i++) {
            cin >> a >> b >> c;
            Add(a, b, c);
        }
        step = n;
        spfa(1);
        sap.init();
        sap.create();
        cout << sap.maxINFlow(1, n) << endl;
    }
    return 0;
}

你可能感兴趣的:(#,做题心得,#,最短路,总结,#,网络流)