poj - 2455 - Secret Milking Machine(最大流+二分)

题意:N个点,P条边(每条边有边长)的无向图,求结点1到结点N的T条路径(每条边只能用一次)中,最长边的最小值(2 <= N <= 200, 1 <= P <= 40,000)。

题目链接:http://poj.org/problem?id=2455

——>>二分答案。。。

建图:设超级源S = 0,S到1连一边容量为T的有向边,连长 <= 答案的双向加入,容量为1,最后N到超级汇T连一条容量为无穷大的有向边。

G++TLE。。。

C++375MS。。。

另外,数组范围要大一点点的样子。。。

#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

const int maxn = 200 + 10;
const int maxm = 400000 + 10;
const int INF = 0x3f3f3f3f;

int N, P, T;
int a[maxm], b[maxm], w[maxm];
int head[maxn], v[maxm<<1], nxt[maxm<<1], cap[maxm<<1], flow[maxm<<1], h[maxn], cur[maxn], ecnt;

struct Dinic {
    int s, t;

    Dinic() {
        memset(head, -1, sizeof(head));
        ecnt = 0;
    }

    void addEdge(int uu, int vv, int ca) {
        v[ecnt] = vv; cap[ecnt] = ca; flow[ecnt] = 0; nxt[ecnt] = head[uu]; head[uu] = ecnt++;
        v[ecnt] = uu; cap[ecnt] = 0; flow[ecnt] = 0; nxt[ecnt] = head[vv]; head[vv] = ecnt++;
    }

    bool bfs() {
        memset(h, -1, sizeof(h));
        h[s] = 0;
        queue<int> qu;
        qu.push(s);
        while(!qu.empty()) {
            int u = qu.front(); qu.pop();
            for(int e = head[u]; e != -1; e = nxt[e])
                if(h[v[e]] == -1 && cap[e] > flow[e]) {
                    h[v[e]] = h[u] + 1;
                    qu.push(v[e]);
                }
        }
        return h[t] != -1;
    }

    int dfs(int u, int a) {
        if(u == t || !a) return a;
        int f, Flow = 0;
        for(int e = cur[u]; e != -1; e = nxt[e]) {
            cur[u] = e;
            if(h[v[e]] == h[u] + 1 && (f = dfs(v[e], min(a, cap[e]-flow[e]))) > 0) {
                flow[e] += f;
                flow[e^1] -= f;
                Flow += f;
                a -= f;
                if(!a) break;
            }
        }
        return Flow;
    }

    int maxflow(int s, int t) {
        this->s = s;
        this->t = t;
        int Flow = 0;
        while(bfs()) {
            memcpy(cur, head, sizeof(head));
            Flow += dfs(s, INF);
        }
        return Flow;
    }
};

bool isok(int len) {
    Dinic din;
    din.addEdge(0, 1, T);
    for(int i = 0; i < P; i++) if(w[i] <= len) {
        din.addEdge(a[i], b[i], 1);
        din.addEdge(b[i], a[i], 1);
    }
    din.addEdge(N, N+1, INF);
    return din.maxflow(0, N+1) == T;
}

int main()
{
    while(scanf("%d%d%d", &N, &P, &T) == 3) {
        int L = INF, R = -1;
        for(int i = 0; i < P; i++) {
            scanf("%d%d%d", &a[i], &b[i], &w[i]);
            if(w[i] < L) L = w[i];
            if(w[i] > R) R = w[i];
        }
        L--;
        R++;
        int ret;
        while(L + 1 < R) {
            int M = (L + R) >> 1;
            if(isok(M)) {
                ret = M;
                R = M;
            }
            else L = M;
        }
        printf("%d\n", ret);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值