[2016ICPC 青岛网络预选赛] HDU 5889 网络流

题意

给一个图,1号点到N号点最短路位L,现在要求删除权值和最小的边,让最短路全部断掉。

思路

让原来的最短路全部断掉,显然一条最短路只要有一个边删掉就可以了,多条最短路构成一个最短路图,割断他的最小代价就是最小割。就是最短路重新建图,然后跑个最大流。

AC代码 C++

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <vector>
#include <functional>

using namespace std;

#define MAXV 1005

struct edge
{
    int to, cost, wei;
    edge(int t, int c, int w) :to(t), cost(c), wei(w) {}
};

template<class T>
struct Dinic {
    const static int N = 2022, M = 20222;
    int s, t, n, h[N], cur[N], level[N], q[N], e, ne[M], to[M];
    T cap[M], flow;
    void liu(int u, int v, T w)
    {
        to[e] = v;
        ne[e] = h[u];
        cap[e] = w;
        h[u] = e++;
    }
    void add_edge(int u, int v, T w)
    {
        liu(u, v, w);
        liu(v, u, 0);
    }
    void init(int _n = N)
    {
        fill(h, h + _n, -1);
        e = 0;
    }
    bool bfs()
    {
        int L = 0, R = 0, c, k;
        fill(level, level + n, -1);
        level[q[R++] = s] = 0;
        while (L < R && level[t] == -1)
        {
            c = q[L++];
            for (k = h[c]; ~k; k = ne[k])
                if (cap[k] > 0 && level[to[k]] == -1)
                    level[q[R++] = to[k]] = level[c] + 1;
        }
        return ~level[t];
    }
    T dfs(int c, T mx)
    {
        if (c == t) return mx;
        T ret = 0;
        for (int &k = cur[c]; ~k; k = ne[k])
            if (level[to[k]] == level[c] + 1 && cap[k] > 0)
            {
                T flow = dfs(to[k], min(mx, cap[k]));
                ret += flow; cap[k] -= flow, cap[k ^ 1] += flow; mx -= flow;
                if (!mx) return ret;
            }
        level[c] = -1;
        return ret;
    }
    T max_flow(int _s, int _t, int _n)
    {
        s = _s, t = _t, n = _n;
        flow = 0;
        while (bfs())
        {
            copy(h, h + n, cur);
            flow += dfs(s, ~0U >> 1);
        }
        return flow;
    }
};

Dinic<int> di;
vector<edge> g[MAXV];
int d[2][MAXV];

void dijkstra(int s, int* d)
{
    int i, v;
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > que;
    d[s] = 0;
    que.push(pair<int, int>(0, s));
    while (!que.empty())
    {
        pair<int, int> p = que.top();
        que.pop();
        v = p.second;
        if (d[v] < p.first)
            continue;
        for (i = 0; i<g[v].size(); i++)
        {
            edge& e = g[v][i];
            if (d[e.to]>d[v] + e.cost)
            {
                d[e.to] = d[v] + e.cost;
                que.push(pair<int, int>(d[e.to], e.to));
            }
        }
    }
}

int main()
{
    int T, n, m, u, v, w, i, j;
    scanf("%d", &T);
    while (T-- && scanf("%d%d", &n, &m))
    {
        for (int i = 0; i <= n; i++)
            g[i].clear();
        for (int i = 0; i<m; i++)
        {
            scanf("%d%d%d", &u, &v, &w);
            g[u].push_back(edge(v, 1, w));
            g[v].push_back(edge(u, 1, w));
        }
        memset(d, 0x3f, sizeof d);
        dijkstra(1, d[0]);
        dijkstra(n, d[1]);
        di.init(n + 5);
        for (i = 1; i <= n; i++)
            for (j = 0; j<g[i].size(); j++)
            {
                v = g[i][j].to;
                w = g[i][j].wei;
                if (d[0][i] + 1 + d[1][v] == d[0][n])
                    di.add_edge(i, v, w);
            }
        printf("%d\n", di.max_flow(1, n, n + 1));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值