网络流复习计划第三题 传送门
啊,这道题的建图完全是自己想的,虽然花的时间比较长,但是还是算是1A了(交了第一发忘记删了文件输入……),老实说,A的有点意外呀……

题意:
小气的农场主发现了个大宝贝并把他藏在了n点,他家在1点,总共n个点有若干条路,谨慎的农场主怕自己的宝贝被偷走,于是要从家里出发,结点不重复的走到大宝贝t次。问你在农场主所走的路径中最长的两点距离最短为多少。

思路:
当然还是二分啦!
先是建立距离图。再二分距离,再额外建图,若两点距离小于等于二分值 limit ,则建立双向建边,流量均为 1 。再跑一次dinic,如果总流量大于等于 t ,说明这个limit是满足条件的,我们再尝试缩小它,否则,增大它。

注意: 此题存在重边,存在重边的图,必须用邻接表存储。为什么来着,突然忘了,以后再补

//wordpress的markdown插件有个bug,代码太长的话头文件就显示不了,现在暂时分开……

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
using namespace std;
const int maxn = 210;
const int inf = 0x3f3f3f3f;

int n, m, c, idx, nidx, st, en;
int dis[maxn][maxn];
int level[maxn], cur[maxn], que[maxn * maxn];
int head[maxn], nhead[maxn];

struct node {
    int to;
    int flow;
    int nxt;
} edges[2 * maxn * maxn], nedges[2 * maxn * maxn];

void addEdge(int u, int v, int flow)
{
    edges[idx].to = v;
    edges[idx].nxt = head[u];
    edges[idx].flow = flow;
    head[u] = idx++;
}

inline void addNetEdge(int u, int v)
{
    nedges[nidx].to = v;
    nedges[nidx].nxt = nhead[u];
    nedges[nidx].flow = 1;
    nhead[u] = nidx++;

    nedges[nidx].to = u;
    nedges[nidx].nxt = nhead[v];
    nedges[nidx].flow = 1;
    nhead[v] = nidx++;
}

inline void createGragh(int limit)
{
    memset(nhead, -1, sizeof head);
    nidx = 0;
    for (int i = 1; i <= n; i++)
        for (int u = head[i]; ~u; u = edges[u].nxt) {
            if (edges[u].flow <= limit) {
                addNetEdge(i, edges[u].to);
            }
        }
}

bool bfs()
{
    memset(level, -1, sizeof level);
    que[0] = st;
    level[st] = 0;
    int l = 0, r = 1, u, v;
    while (l < r) {
        u = que[l++];
        for (int i = nhead[u]; ~i; i = nedges[i].nxt) {
            v = nedges[i].to;
            if (nedges[i].flow && level[v] == -1) {
                level[v] = level[u] + 1;
                que[r++] = v;
            }
        }
    }
    return level[en] != -1;
}

int dfs(int u, int low)
{
    int cflow;
    if (u == en)
        return low;
    for (int& i = cur[u]; ~i; i = nedges[i].nxt) {
        int v = nedges[i].to;
        if (nedges[i].flow > 0 && level[v] == level[u] + 1
            && (cflow = dfs(v, min(low, nedges[i].flow)))) {
            nedges[i].flow -= cflow;
            nedges[i ^ 1].flow += cflow;
            return cflow;
        }
    }
    return 0;
}

int dinic()
{
    st = 1, en = n;
    int ans = 0, cflow;
    while (bfs()) {
        for (int i = 1; i <= n; i++)
            cur[i] = nhead[i];
        while ((cflow = dfs(st, inf)))
            ans += cflow;
    }
    return ans;
}

void init()
{
    idx = 0;
    memset(head, -1, sizeof head);
}

int main()
{
    int u, v, w;
    while (scanf("%d %d %d", &n, &m, &c) != EOF) {
        init();
        int l = 0, r = 0, mid;
        while (m--) {
            scanf("%d %d %d", &u, &v, &w);
            addEdge(u, v, w);
            r = max(r, w);
        }
        while (l <= r) {
            mid = (l + r) >> 1;
            createGragh(mid);
            if (dinic() >= c)
                r = mid - 1;
            else
                l = mid + 1;
        }
        printf("%d\n", r + 1);
    }
    return 0;
}