HDU 6598 Harmonious Army【最小割_网络流建图】

题目链接


题意:

  • n个士兵,m组信息:u v a b c。对于士兵u v:如果都是战士(Warrior),那么军队power增加a;如果都是法师(Mage),那么军队power增加c;如果一个是战士,一个是法师,那么军队power增加b. 其中 b = a / 4 + c / 3 b = a/4+c/3 . 问军队power最大是多少?

思路

  • 如果每个士兵可以选择两个职位,那么军队 p o w e r = i = 0 m ( a [ i ] + b [ i ] + c [ i ] ) power=\displaystyle \sum^{m}_{i = 0}{(a[i]+b[i]+c[i])} .
  • 但是每个士兵只能选择一个职位啊,咋办?嘤?
  • 我们假设s是战士Warrior阵营,t是法师Mage阵营。对于一对有关系的士兵uv建图如下。我们需要构造出ABCDE的权值,使得上述军队 p o w e r = i = 0 m ( a [ i ] + b [ i ] + c [ i ] ) power=\displaystyle \sum^{m}_{i = 0}{(a[i]+b[i]+c[i])} .减去图中最小割为答案。

在这里插入图片描述
显然有以下四种情况(请您细细品味. 你品,你细品~)

  • A + B = a + b A+B = a+b 【若uv同属法师阵营,此时所能贡献的power是c,那么需要割掉AB两条边,值为a+b】
  • C + D = b + c C+D = b+c 【若uv同属战士阵营,此时所能贡献的power是a,那么需要割掉CD两条边,值为b+c】
  • A + E + D = a + c A+E+D=a+c 【u是法师,v是战士,此时所能贡献的power是b,那么需要割掉AED,值为a+c】
  • B + E + C = a + c B+E+C=a+c 【u是战士,v是法师,此时所能贡献的power是b,那么需要割掉BEC,值为a+c】

由此我们可以得到边权的一组解,如下:

  • A = B = ( a + b ) / 2 A=B=(a+b)/2
  • C = D = ( c + b ) / 2 C=D=(c+b)/2
  • E = ( a + c ) / 2 b E=(a+c)/2-b

虽然题目限定 a 4 a|4 b 3 b|3 ,但是我们构造出的ABCDE仍然可能会出现浮点数,所以我们将图中所有边权都设定为构造出的二倍,那么真正的最小割也就是求出的一半~这样可以避免出现浮点数


(二)、对于此题还有一种理解方式【建图仍然和上述相同】

  比如说:若uv同属法师阵营,此时所能贡献的power是c,那么需要割掉AB两条边,值为 a + b a+b ,我们又知道 b = a / 4 + c / 3 b=a/4+c/3 ,于是可以得到 A + B = a + b = a + a / 4 + c / 3 = 5 a 4 + c 3 A+B=a+b=a+a/4+c/3=\displaystyle \frac{5a}{4}+\displaystyle \frac{c}{3} ,那么直接可以得到 A = B = A + B 2 = 5 a 8 + c 6 A=B=\displaystyle \frac{A+B}{2}=\displaystyle \frac{5a}{8}+\displaystyle \frac{c}{6}

  同理,若uv同属战士阵营,此时所能贡献的power是a,那么需要割掉CD两条边,值为 b + c b+c ,于是可以得到 C = D = C + D 2 = a 8 + 4 c 6 C=D=\displaystyle \frac{C+D}{2}=\displaystyle \frac{a}{8}+\displaystyle \frac{4c}{6}

  同理,若uv一个战士一个法师,那么贡献的power是b,需要割掉AED或BEC,也就是 A + E + D = a + c A+E+D=a+c 可以计算得到, E = a 4 + c 6 E=\displaystyle \frac{a}{4}+\displaystyle \frac{c}{6}

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
inline int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

const int maxN = 505;
const int maxM = 60004;

int n, m, s, t;

struct EDGE{
    int adj, to;
    ll w;
    EDGE(int a = -1, int b = 0, ll c = 0): adj(a), to(b), w(c) {}
}edge[maxM];
int head[maxN], cur[maxN], cnt;
int deep[maxN];

void init()
{
    memset(head, -1, sizeof(head));
    cnt = 0;
}

void add_edge(int u, int v, ll w)
{
    edge[cnt] = EDGE(head[u], v, w);
    head[u] = cnt ++ ;
}

bool bfs()
{
    for(int i = 0; i <= n + 2; ++ i ) deep[i] = 0, cur[i] = head[i];
    queue<int>q;
    q.push(s); deep[s] = 1;
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = head[u]; ~i; i = edge[i].adj)
        {
            int v = edge[i].to;
            if(!deep[v] && edge[i].w)
            {
                deep[v] = deep[u] + 1;
                q.push(v);
            }
        }
    }
    return deep[t];
}

ll dfs(int u, ll flow)
{
    if(u == t || !flow) return flow;
    for(int &i = cur[u]; ~i; i = edge[i].adj)
    {
        int v = edge[i].to;
        if(deep[v] == deep[u] + 1 && edge[i].w)
        {
            if(ll newFlow = dfs(v, min(flow, edge[i].w)))
            {
                edge[i].w -= newFlow;
                return newFlow;
            }
        }
    }
    return 0;
}

ll dinic()
{
    ll maxFlow = 0;
    while(bfs())
    {
        while(ll newFlow = dfs(s, INF))
            maxFlow += newFlow;
    }
    return maxFlow;
}

int main()
{
    while(~scanf("%d%d", &n, &m))
    {
        init();
        s = n + 1, t = n + 2;
        ll ans = 0;
        for(int i = 0; i < m; ++ i )
        {
            int u, v, a, b, c;
            u = read(); v = read(); a = read(); b = read(); c = read();
            ans += (a + b + c);
            ll A, B; A = B = a + b;
            ll C, D; C = D = b + c;
            ll E; E = a + c - 2 * b;
            add_edge(s, u, A);
            add_edge(s, v, B);
            add_edge(u, v, E);
            add_edge(v, u, E);
            add_edge(u, t, C);
            add_edge(v, t, D);
        }
        ans -= (dinic() >> 1);
        printf("%lld\n", ans);
    }
    return 0;
}
发布了273 篇原创文章 · 获赞 76 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104758740