题目链接
题意:
- n个士兵,m组信息:u v a b c。对于士兵u v:如果都是战士(Warrior),那么军队power增加a;如果都是法师(Mage),那么军队power增加c;如果一个是战士,一个是法师,那么军队power增加b. 其中 . 问军队power最大是多少?
思路
- 如果每个士兵可以选择两个职位,那么军队 .
- 但是每个士兵只能选择一个职位啊,咋办?嘤?
- 我们假设s是战士Warrior阵营,t是法师Mage阵营。对于一对有关系的士兵uv建图如下。我们需要构造出ABCDE的权值,使得上述军队 .减去图中最小割为答案。
显然有以下四种情况(请您细细品味. 你品,你细品~)
- 【若uv同属法师阵营,此时所能贡献的power是c,那么需要割掉AB两条边,值为a+b】
- 【若uv同属战士阵营,此时所能贡献的power是a,那么需要割掉CD两条边,值为b+c】
- 【u是法师,v是战士,此时所能贡献的power是b,那么需要割掉AED,值为a+c】
- 【u是战士,v是法师,此时所能贡献的power是b,那么需要割掉BEC,值为a+c】
由此我们可以得到边权的一组解,如下:
虽然题目限定 且 ,但是我们构造出的ABCDE仍然可能会出现浮点数,所以我们将图中所有边权都设定为构造出的二倍,那么真正的最小割也就是求出的一半~这样可以避免出现浮点数
(二)、对于此题还有一种理解方式【建图仍然和上述相同】
比如说:若uv同属法师阵营,此时所能贡献的power是c,那么需要割掉AB两条边,值为 ,我们又知道 ,于是可以得到 ,那么直接可以得到
同理,若uv同属战士阵营,此时所能贡献的power是a,那么需要割掉CD两条边,值为 ,于是可以得到
同理,若uv一个战士一个法师,那么贡献的power是b,需要割掉AED或BEC,也就是 可以计算得到,
#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;
}