zoj2676 Network Wars(0-1分数规划,最大流模板)

Network Wars

07年胡伯涛的论文上的题:http://wenku.baidu.com/view/87ecda38376baf1ffc4fad25.html

代码:

#include <algorithm>
#include <cstdio>
#include <iterator>
#include <limits>
#include <vector>
#include <string.h>

const int N = 111;
const int M = 404;
const double EPS = 1e-3;

typedef std::vector<int> VI;

int signum(double x) {
    return x > EPS ? 1 : (x < -EPS ? -1 : 0);
}

template<int N, int M, class Flow>
struct Dinic {
    int n, e, first[N], cur[N], next[M], to[M], id[M], s, t;
    int pre[N], level[N], q[N], sign;
    Flow cap[M], flow;
    void add(int u, int v, Flow w, int i) {
        to[e] = v;
        cap[e] = w;
        id[e] = i;
        next[e] = first[u];
        first[u] = e++;
    }
    bool bfs(int s, int t) {
        std::fill(level+1, level + n + 1, -1);
        sign = t;
        level[t] = 0;
        int head = 0, tail = 0;
        q[tail++] = t;
        while (head != tail && level[s] == -1) {
            int u = q[head++];
            for (int it = first[u]; it != -1; it = next[it]) {
                if (cap[it ^ 1] > 0 && level[to[it]] == -1) {
                    level[to[it]] = level[u] + 1;
                    q[tail++] = to[it];
                }
            }
        }
        return level[s] != -1;
    }
    void push() {
        Flow delta = std::numeric_limits<Flow>::max();
        int u, p;
        for (u = t; u != s; u = to[p ^ 1]) {
            p = pre[u];
            delta = std::min(delta, cap[p]);
        }
        for (u = t; u != s; u = to[p ^ 1]) {
            p = pre[u];
            cap[p] -= delta;
            if (!cap[p]) {
                sign = to[p ^ 1];
            }
            cap[p ^ 1] += delta;
        }
        flow += delta;
    }
    void dfs(int u) {
        if (u == t) {
            push();
        } else {
            for (int & it = cur[u]; it != -1; it = next[it]) {
                if (cap[it] > 0 && level[u] == level[to[it]] + 1) {
                    pre[to[it]] = it;
                    dfs(to[it]);
                    if (level[sign] > level[u]) {
                        return;
                    }
                    sign = t;
                }
            }
            level[u] = -1;
        }
    }
    void init(int _n, int _s, int _t) {
        n = _n, s = _s, t = _t;
        std::fill(first + 1 , first + n + 1 , -1);
        e = 0;
    }
    Flow solve() {
        flow = 0;
        while (bfs(s, t)) {
            for (int i = 1; i <= n; ++i) {
                cur[i] = first[i];
            }
            dfs(s);
        }
        return flow;
    }
};

Dinic<N,M<<1,double> AC ;
int left[M] , right[M] , w[M] ;
int n , m , mark[M] ;

double judge ( double key ) {
    double sum = 0 ;
    memset ( mark , 0 , sizeof ( mark ) ) ;
    AC.init ( n , 1 , n ) ;
    for ( int i = 1 ; i <= m ; i ++ )
        if ( w[i] <= key ) {
            sum += w[i] - key ;
            mark[i] = 1 ;
        } else {
            AC.add ( left[i] , right[i] , w[i] - key , i ) ;
            AC.add ( right[i] , left[i] , w[i] - key , i ) ;
        }
    double add = AC.solve () ;
    sum += add ;
    return sum ;
}

void solve () {
    double l = 0 , r = (double) m * 1e7 ;
    while ( signum (r-l) > 0 ) {
        double mid = ( l + r ) / 2.0 ;
        double k = judge ( mid ) ;
        if ( signum ( k ) >= 0 ) l = mid ;
        else r = mid ;
    }
    AC.bfs ( 1 , n ) ;
    for ( int i = 0 ; i < AC.e ; i ++ ) {
        int u = AC.to[i^1] , v = AC.to[i] ;
        if ( AC.level[u] == -1 && AC.level[v] != -1 )
        mark[AC.id[i]] = 1 ;
    }
    int ans = 0 ;
    for ( int i = 1 ; i <= m ; i ++ ) if ( mark[i] ) ans ++ ;
    printf ( "%d\n" , ans ) ;
    for ( int i = 1 ; i <= m ; i ++ ) if ( mark[i] ) printf ( "%d " , i ) ;
    puts ( "" ) ;
}

int main () {
 //   freopen("network.in", "r", stdin);
 //   freopen("network.out", "w", stdout);
    int flag = 0 ;
    while ( scanf ( "%d%d" , &n , &m ) != EOF ) {
        for ( int i = 1 ; i <= m ; i ++ )
            scanf ( "%d%d%d" , &left[i] , &right[i] , &w[i] ) ;
        if ( flag ) puts ( "" ) ;
        flag = 1 ;
        solve () ;
    }
    return 0 ;
}
时间: 2024-10-08 22:17:45

zoj2676 Network Wars(0-1分数规划,最大流模板)的相关文章

bzoj 3232 圈地游戏——0/1分数规划(或网络流)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3232 当然是0/1分数规划.但加的东西和减的东西不在一起,怎么办? 考虑把它们合在一起.因为边围成的形状像一个环,所以把格子的贡献也放到边上,然后正常判环. 放到边上的方法就是:比如竖着的边,可以在每一行上维护该行格子值前缀和,然后指定那个围成的形状是,比如,逆时针的,那么向上的边就加上到它为止的前缀值,向下的边就减去到它为止的前缀值,然后就能判环了! 这样一定只有一个环.但多个环答案不会

0/1分数规划

学习了lyd书上的0/1分数规划,发现这类题目都有一个特点,就是求$\frac{\sum_{a_{i}*x_{i}}}{\sum_{b_{i}*x_{i}}}$的最大或者最小,再加一些限制取不取的条件. POJ2976 二分答案+sort取前(n-k+1)个. #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; con

POJ - 2976 Dropping tests &amp;&amp; 0/1 分数规划

POJ - 2976 Dropping tests 你有 \(n\) 次考试成绩, 定义考试平均成绩为 \[\frac{\sum_{i = 1}^{n} a_{i}}{\sum_{i = 1}^{n} b_{i}}\] 你可以考虑放弃 \(K\) 次成绩, 求最大平均成绩 * 100 小插曲: 被精度卡成喜羊羊 0/1分数规划\(from\)人生导师 Solution 01分数规划(不是很)裸题, 在每次 \(check\) 时, 选取较大的 \(num - K + 1\) 次即可 Code #

2019.4.9 一题——概率期望+0/1分数规划+最大权闭合子图

没注意 “第 x 条边和第 y 条边的起点是相同的” 的限制.没想出来. 有这个限制,可以考虑每个点分别计算.令 \( f[i] \) 表示从 i 出发的最大边数期望,那么先把拓扑序在自己之后的点的 \( f[ ] \) 算出来,然后考虑自己这个点的出边怎么做能使自己的 \( f[ ] \) 最大. \( f[i]=\frac{ \sum f[j]+1 }{ d } \) ,其中 d 是保留下来的边数, j 是保留边指向的点. 如果把 \( f[ ]+1 \) 看做收益, 1 看做代价,那么这个

『0/1分数规划 二分法』

0/1分数规划 模型 0/1分数规划指的是这样一个问题模型: 给定整数\(a_1,a_2,...,a_n\)和\(b_1,b_2,...,b_n\),求一组解\(x_1,x_2,...,x_n(\forall\ i\in[1,n],x_i=1,0)\),使得下式最大化:\[\frac{\sum_{i=1}^na_i*x_i}{\sum_{i=1}^nb_i*x_i}\] 简单地说,就是给定\(n\)对整数\(a_i,b_i\),从中选取若干对,使得选出的\(a\)之和与\(b\)之和的比值最大.

[例题/总结]0/1分数规划

[TOC] ##一.总述 0/1分数规划是专门解决0/1分数规划模型的一种算法~~(废话)~~.所以说0/1分数规划模型是什么呢?给定整数{\(a_1,a_2,a_3,...,a_n\)},{\(b_1,b_2,b_3,...,b_n\)}从中选出若干对数,使得它们各自和的比值最大.公式如下: \(\frac{\sum_{p=1}^{n}a_p\times x_p}{\sum_{p=1}^{n}b_p\times x_p}(x_p=1,0)\) ##二.实现原理 那么我们用什么方法可以求出这样一

【bzoj4819】[Sdoi2017]新生舞会 分数规划+费用流

题目描述 学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴.有n个男生和n个女生参加舞会买一个男生和一个女生一起跳舞,互为舞伴.Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出 a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度.Cathy还需要考虑两个人一起跳舞是否方便,比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度.当然,还需要考虑很多其他问题.Cathy想先用一个程序通过a

zoj2676--Network Wars(0-1分数规划+最小割)

zoj2676:题目链接 题目大意:有一个n个点的网络,其中有m条光缆(所有的点都被连接,任意两个点之间最多有一条,不存在连接自身的),每条光缆有一定的价值,网络中1为起点,n为终点,现在要求找出一些光缆能分割开1到n,使它们不能相互通信,并且要求花费的和除以光缆数的值最小.输出选择的光缆的编号. 从问题中可以看出一定是0-1分数规划的题目,假设选出光缆的集合M,M为原图的一个割,光缆si∈M,价值为ci,数量k = 1 ,可以推出g(x) = min( ∑c - x*∑k ),因为si是割中的

Yougth的最大化(好题,二分查找 0 1分数规划)

Yougth的最大化 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 Yougth现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从中选出k个物品使得单位重量的价值最大吗? 输入 有多组测试数据每组测试数据第一行有两个数n和k,接下来一行有n个数Wi和Vi.(1<=k=n<=10000) (1<=Wi,Vi<=1000000) 输出 输出使得单位价值的最大值.(保留两位小数) 样例输入 3 2 2 2 5 3 2 1 样例输出 0.75 1 #in