原题解链接:https://ac.nowcoder.com/discuss/154293
先将 求和,然后将选择/不选择视为在此基础上付出代价,问题就转化为了求最小代价。
对于每个约束,考虑如下的一个图,表示源点和汇点,表示跟这个约束相关的两把剑,表示权值
将割掉到某一把剑的边视为不选择 ,割掉到的边视为选择。
要使不连通,割有四种(注意逗号)
设 表示选择能得到的攻击力, 表示选择能得到的攻击力, 表示 都选时额外获得的攻击力, 表示都不选时额外获得的攻击力, 表示只选一个时扣除的攻击力
可得
, 都不选
都选
(不选 ,选 )
(选 ,不选 )
只需要求出一组合法的解,人为构造
最小代价即这张图的最小割
复杂度取决于使用的网络流算法,不过应该是都能通过的
#include <bits/stdc++.h>
using namespace std;
typedef long long lo;
lo n, m, opt, lx, ly, tot = -1, head[1007], he[1007], q[1007], t, de[1007], w[1007], W[1007], ans, v0, v1, v2;
struct in
{
lo to, ne; lo co;
};
vector<in>ter;
inline void build(lo f, lo l, lo c)
{
ter.push_back((in) {l, head[f], c}), head[f] = ++tot;
}
inline bool bfs()
{
queue<int>q;
memset(de, 0, sizeof(de)), de[0] = 1; q.push(0);
while (!q.empty()) {
lo qaq = q.front(); q.pop();
for (lo i = head[qaq]; i >= 0; i = ter[i].ne)
{
lo to = ter[i].to;
if (ter[i].co && (!de[to]))
de[to] = de[qaq] + 1, q.push(to);
}
}
return de[t] > 0;
}
lo dfs(lo no, lo fl)
{
if (no == t || (!fl))
return fl;
lo rt = 0, c;
for (lo &i = he[no]; i >= 0; i = ter[i].ne)
{
lo to = ter[i].to;
if (ter[i].co && de[to] == de[no] + 1)
{
c = dfs(to, min(fl, ter[i].co));
if (c)
{
fl -= c, rt += c, ter[i].co -= c, ter[i ^ 1].co += c;
if (fl <= 0)
return rt;
}
}
}
return rt;
}
bool flag[1007];
int main()
{
scanf("%lld%lld", &n, &m);
t = n + 1; memset(head, -1, sizeof(head));
for (int i = 1; i <= n; i ++)
scanf("%lld", w + i), ans += w[i];
for (int i = 1; i <= m; i ++)
{
scanf("%lld%lld%lld%lld%lld", &lx, &ly, &v0, &v1, &v2);
ans += v0 + v1;
W[lx] += v1 / 2, W[ly] += v1 / 2, w[lx] += v0 / 2, w[ly] += v0 / 2;
build(lx, ly, (v0 + v1) / 2 + v2), build(ly, lx, (v0 + v1) / 2 + v2);
}
for (int i = 1; i <= n; i ++)
build(0, i, w[i]), build(i, 0, 0), build(i, t, W[i]), build(t, i, W[i]);
lo tmp;
while (bfs())
{
memcpy(he, head, sizeof(he));
while ((tmp = dfs(0, 1e13 + 7)) > 0)
ans -= tmp;
}
printf("%lld", ans);
return 0;
}