ZOJ 3764 - ZOJ Monthly, March 2014 最大流最小割

来源:互联网 发布:js 大屏幕 倒计时特效 编辑:程序博客网 时间:2024/06/05 01:07

原题:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3764

题意:给定一个N个点M条边的带权图,你可以删掉不超过K条边,求删边后图的最大流最小是多少 (N  <= 10, M <= 1000, K <= M)


解题思路:

平时我们经常是用最大流求最小割,这次的思路反过来,降低最小割来减少最大流

考虑一个图的最小割,他将一个图划分成两个集合,源和汇各属一个集合,最小割割掉了连接这两个集合的边

那么由于我们现在可以预先删除K条边,所以我们可以将连接两个集合的边中,前K大的先删掉,剩下的加起来就是还需要割的

也就是当前情况下的最大流


最终的解法就是枚举集合的分法,然后搞一搞就行了...


代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;#define LL long long#define eps 1e-8#define mxn 15#define mxe 5005const LL INF = 2100000000000000LL;struct edge {    int u, v, c;    bool operator < (const edge& b) const {        return c > b.c;    }}E[mxe];LL solve( int msk, int n, int m, int k ) {    if( (msk & 1) == ((msk >> (n - 1)) & 1) )        return INF;    LL ret = 0;    for( int i = 0; i < m; ++i ) {        int u = E[i].u, v = E[i].v, c = E[i].c;        if( ((msk >> (u - 1)) & 1) ^ (((msk >> (v - 1)) & 1)) ) {            if( k )                --k;            else ret += c;        }    }    return ret;}int main(){    int n, m, k;    while( scanf( "%d%d%d", &n, &m, &k ) == 3 ) {        for( int i = 0; i < m; ++i )            scanf( "%d%d%d", &E[i].u, &E[i].v, &E[i].c );        sort(E, E + m);        LL ans = INF;        for( int i = 0; i < (1 << n); ++i )            ans = min(ans, solve(i, n, m, k));        cout << ans << endl;    }    return 0;}


0 0
原创粉丝点击