Harmonious Army 【HDU - 6598】【最小割】

题目链接


  很经典的一道问题,应该是二刷了,但是刷第二遍的时候还是有很深刻的体会。

  题意:有N个人,每个人都有自己所可选的阵营,战士或者是法师,现在给出M个关系对,如果关系对中的两个人都是战士会得到贡献a,如果一战士一法师会得到贡献b,如果两个法师会得到贡献c,现在求最大贡献。

  好了,我们来思考这个问题,有N个人,他们每个人该选择战士还是法师呢?肯定是由他的贡献来确定的,如果现在有X和Y两个人,若他两都选择了战士,那么他们将舍弃贡献是b+c,如果他两都选择了法师,则他们舍弃贡献a+b,如果一个是战士一个是法师那么舍弃的贡献呢就是a+c。

  那么,我们假设我们一开始有\sum(a_i + b_i + c_i)的贡献,现在呢,我们希望舍去最少的贡献,好了,这个问题似乎变成了最小割!最小需要割去的贡献!如何建立这个最小割模型呢?

  很容易想到的割法就是一边是选择战士,一边是选择法师,于是一个点,选择战士的去连接上S源点,选择法师的去连接上T汇点,这样对一个点的贡献就好求了,但是没有哪个贡献是只给一个点的,所以必须考虑到两个点的情况下。

  类似于这样,选择战士所要拿走的贡献为A+B=b+c,而选择法师所要取走的贡献为C+D=a+b,可是光这样的话,选择一个战士一个法师的情况该如何解决呢?所以我们还需要解决一个很实际的问题,就是如果我们拿走的是一个战士一个法师的情况下,也就是说明一边选战士一边选法师,诶!那么是不是X和Y之间连接条边就可以了,而且这条边还比较的特殊,只有让他变成一个无向边才可以满足我们的需求,因为它要么使得一边成为战士一边成为法师,所以说它不确定是那一边战士哪一边法师,所以无向边才能解决我们现在面临的问题。

  我用红色标明了我新添加的这条边。

  现在,我们形成了方程组了:

A + B = b + c

C + D = a + b

A + E + D = B + E + C = a + c

  小写表示的是原来的a、b、c,大写是我们给边对应的权值。

  我们可以知道的是A == B,并且呢,C == D。然后我们就可以确定完整的A、B、C、D、E各自的值了。

  于是,根据A、B、C、D、E的值,我们建图跑最大流,用总和减去自然就是我们要的答案了。

  此题中,可能存在".5"这样的小数,所以呢,我给所有的边权都“ * 2 ”来避免出现浮点数了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
#define MAX_3(a, b, c) max(a, max(b, c))
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 5e2 + 7, maxM = 1e5 + 7;
int N, M, head[maxN], cnt, cur[maxN];
struct Eddge
{
    int nex, to; ll flow;
    Eddge(int a=-1, int b=0, ll c=0):nex(a), to(b), flow(c) {}
}edge[maxM];
inline void addEddge(int u, int v, ll w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
inline void _add(int u, int v, ll w) { addEddge(u, v, w); addEddge(v, u, 0); }
struct Max_Flow
{
    int gap[maxN], d[maxN], que[maxN], ql, qr, S, T, node;
    inline void init()
    {
        for(int i=0; i<=node + 1; i++)
        {
            gap[i] = d[i] = 0;
            cur[i] = head[i];
        }
        ++gap[d[T] = 1];
        que[ql = qr = 1] = T;
        while(ql <= qr)
        {
            int x = que[ql ++];
            for(int i=head[x], v; ~i; i=edge[i].nex)
            {
                v = edge[i].to;
                if(!d[v]) { ++gap[d[v] = d[x] + 1]; que[++qr] = v; }
            }
        }
    }
    inline ll aug(int x, ll FLOW)
    {
        if(x == T) return FLOW;
        ll flow = 0;
        for(int &i=cur[x], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            if(d[x] == d[v] + 1)
            {
                ll tmp = aug(v, min(FLOW, edge[i].flow));
                flow += tmp; FLOW -= tmp; edge[i].flow -= tmp; edge[i ^ 1].flow += tmp;
                if(!FLOW) return flow;
            }
        }
        if(!(--gap[d[x]])) d[S] = node + 1;
        ++gap[++d[x]]; cur[x] = head[x];
        return flow;
    }
    inline ll max_flow()
    {
        init();
        ll ret = aug(S, INF);
        while(d[S] <= node) ret += aug(S, INF);
        return ret;
    }
} mf;
inline void init()
{
    cnt = 0; mf.S = 0; mf.T = N + 1; mf.node = mf.T + 1;
    for(int i=0; i<=mf.node; i++) head[i] = -1;
}
int main()
{
    while(scanf("%d%d", &N, &M) != EOF)
    {
        init();
        ll sum = 0, A, B, C, D, E;
        for(int i=1, u, v, a, b, c; i<=M; i++)
        {
            scanf("%d%d%d%d%d", &u, &v, &a, &b, &c);
            sum += a + b + c;
            A = B = a / 4 + 4 * c / 3;
            C = D = 5 * a / 4 + c / 3;
            E = a / 2 + c / 3;
            _add(mf.S, u, A);
            _add(mf.S, v, B);
            _add(u, mf.T, C);
            _add(v, mf.T, D);
            addEddge(u, v, E);
            addEddge(v, u, E);
        }
        printf("%lld\n", sum - mf.max_flow() / 2LL);
    }
    return 0;
}
发布了852 篇原创文章 · 获赞 1016 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/104840079