Codeforces 653D Delivery Bears【二分+网络流】

题目链接:

http://codeforces.com/problemset/problem/653/D

题意:

x个熊拿着相同重量的物品,从1号结点沿着路走到N号结点,结点之间有边相连,保证可以从1号走到N号。

The total weight that travels across a particular edge must not exceed the weight capacity of that edge.

所有经过这条边的熊,他们所拿的重量之和不能大于这条边的容量。
求所有熊所能拿的最大重量之和。

分析:

很明显的网络流。
理解了题意便可以想到直接二分每个熊可以拿的重量,每边的容量代表经过熊的个数,这样在每次judge的时候对边进行处理,判断是否满流就好啦~~~

代码:

#include<cstdio>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
typedef pair<int, int>pii;
#define fi first
#define se second
struct edge{int to, cap, rev;};
const int maxn = 10005, maxm = 20100, INF = 0x3f3f3f3f;
int d[maxm], iter[maxm];
int s, t;
int x, m;
int n, q;
vector<edge>G[maxm];
pii u[maxn];
int a[maxn], b[maxn], c[maxn];
void add_edge(int from, int to, int cap)
{
    G[from].push_back((edge){to, cap, G[to].size()});
    G[to].push_back((edge){from, 0, G[from].size()-1});
}
void bfs()
{
    memset(d, -1, sizeof(d));
    queue<int>q;
    d[s] = 0;
    q.push(s);
    while(!q.empty()){
        int v = q.front();q.pop();
        for(int i = 0; i <G[v].size(); i++){
            edge &e = G[v][i];
            if(e.cap>0&&d[e.to]<0){
                d[e.to] = d[v] + 1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int v, int f)
{
    if(v == t) return f;
    for(int &i = iter[v]; i < G[v].size(); i++){
        edge &e = G[v][i];
        if(e.cap > 0 && d[v] < d[e.to]){
            int tf = dfs(e.to, min(f, e.cap));
            if(tf > 0){
                e.cap -= tf;
                G[e.to][e.rev].cap +=tf;
                return tf;
            }
        }
    }
    return 0;
}
int max_flow()
{
    int flow = 0;
    for(;;){
        bfs();
        if(d[t]<0) return flow;
        memset(iter, 0, sizeof(iter));
        int f;
        while((f = dfs(s, INF))>0){
            flow += f;
        }
    }
}
bool judge(double mid)
{
    for(int i = 0; i < maxn; i++)
        G[i].clear();
    for(int i = 0; i < m; i++){
        add_edge(a[i], b[i], min(1.0 * x, (double)c[i]/mid));//注意容量可能会爆int,所以取和x的最小值就好~
    }
    add_edge(n, t, x);
    add_edge(s, 1, x);
    return max_flow() == x;
}
int main (void)
{
    scanf("%d%d%d",&n, &m, &x);
    for (int i = 0; i < m; i++){
         scanf("%d%d%d", &a[i], &b[i], &c[i]);
    }
    s = 0, t = n + 1;
    add_edge(n, t, INF);
    add_edge(s, 1, x);

    double l = 0, r = 1000005;
    for(int i = 0; i < 100; i++){
        double mid = (l + r)/2;
        if(judge(mid)) l  = mid;
        else r = mid;
    }
   printf("%.10f", l*x);
}

posted @ 2016-03-21 18:04  zhuyujiang  阅读(250)  评论(0编辑  收藏  举报