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

原题: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 5005

const 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;
}


你可能感兴趣的:(ZOJ 3764 - ZOJ Monthly, March 2014 最大流最小割)