题解:HDU 6598

Description

Now, Bob is playing an interesting game in which he is a general of a harmonious army. There are \(n\) soldiers in this army. Each soldier should be in one of the two occupations, Mage or Warrior. There are \(m\) pairs of soldiers having combination ability. There are three kinds of combination ability. If the two soldiers in a pair are both Warriors, the army power would be increased by \(a\). If the two soldiers in a pair are both Mages, the army power would be increased by \(c\). Otherwise the army power would be increased by \(b\), and \(b=a/4+c/3\), guaranteed that \(4|a\) and \(3|c\). Your task is to output the maximum power Bob can increase by arranging the soldiers' occupations.

Note that the symbol \(a|b\) means that \(a\) divides \(b\), e.g. , \(3|12\) and \(8|24\).

\(n \leq 500,\ m \leq 10^4\)

多组数据,保证\(\sum n \leq 5 * 10 ^3,\ \sum m \leq 5 * 10^4\)

题意:给 \(n\) 个点染上两种颜色。现在给出 \(m\) 种形如 \((u, v, a, b, c)\) 的关系

如果点 \(u, v\) 同为颜色1,则获得 \(a\) 的收益;

如果点 \(u, v\) 同为颜色2,则获得 \(c\) 的收益;

如果点 \(u, v\) 颜色不同,则获得 \(b\) 的收益。

现在求所有染色方案中可获得的最大收益。

Algorithm

题意与数据范围无处不提示我们:这题网络流。

阅题无数的同学们可能会想到文理分科这道题目(https://www.luogu.com.cn/problem/P4313),

确实,虽然具体处理上有差别,本题与文理分科的模型是很相似的。

首先考虑如何表示「染色」。我们考虑建立两个新点 \(s, t\) 。

接下来考虑某个特定点 \(u\) ,

如果将点 \(u\) 染成颜色1,就建立一条\(s \to u\) 的边;

对应地,如果将点 \(u\) 染成颜色2,就建立一条 \(u \to t\) 的边。

同一个点不可能被染成两种颜色,因此不应该存在一条 \(s \to \dots \to t\) 的路径。

当然,如果正面考虑如何建边的话就和暴力没什么两样了。

然而,我们可以考虑将所有边建好之后再删去其中的一些,使得删去的边权值和最小。

换言之,我们只需要求出 \(s \to t\) 的最小割即可。

框架已经放好了,接下来要考虑的就是如何建图了。

特别地,我们考虑某个关系 \((u, v, a, b, c)\)

建立边 $s \to u,\ s \to v, \ u \to t, \ v \to t, \ u \leftrightarrow v $,设各边权值如图。

这里我们建立了一条 \(u \leftrightarrow v\) 的双向边,用以控制两点染上不同颜色获得的收益值。

若点 \(u, v\) 均与 \(t\) 联通,则需要删去边 \(s \to u,\ s \to v\),

这时只能获得 \(c\) 的收益,而不能获得 \(a + b\) 的收益,那么有 \(x_1 + x_2 = a + b\)。

同理我们有 \(y_1 + y_2 = b + c\)。

接下来考虑两点分别染上不同颜色的情况。

先考虑 \(u\) 与 \(s\) 联通,\(v\) 与 \(t\) 联通的情况,我们此时要删去 \(s \to v,\ v \to u,\ u \to t\) 共三条边,

损失的收益为 \(a + c\) ,于是有 \(x_2 + z + y_1 = a + c\) 。

同理我们有 \(x_1 + z + y_2 = a + c\) 。

综合,我们得到方程组:

\[\cases{x_1 + x_2 = a + b \\ y_1 + y_2 = b + c \\ x_2 + z + y_1 = a + c \\ x_1 + z + y_2 = a + c}
\]

考虑到\(x_1, x_2\) 或 \(y_1, y_2\) 的地位应当相等,容易得到一组解:

\[\cases{x_1 = x_2 = \frac{a + b}{2} \\ y_1 = y_2 = \frac{b + c}{2} \\ z = \frac{a+c}{2} - b}
\]

考虑到除以二可能会导致不必要的精度误差,可以全部乘二再建图。

由众所周知的最小割等于最大流,我们在图上跑一边dinic就没事了。

最后的答案是

\[\sum (a + b + c) - \frac{Maxflow}{2}
\]

代码在细节上可能有些小小的不一样,毕竟是考场写的和博客说的肯定不太一样。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std; template<typename T>
inline void read(T &x)
{
char c = getchar(); x = 0;
while(c < '0' || '9' < c) c = getchar();
while('0' <= c && c <= '9')
{
x = (x << 1) + (x << 3) + c - 48;
c = getchar();
}
} typedef long long ll;
const ll INF = 1e18;
template<const int N, const int M>
class Graph {
private:
int beg[N], nex[M], tar[M], len;
int lev[N], ite[N], goa;
ll cap[M];
queue<int> que; public:
inline void clear()
{
memset(beg, 0, sizeof(beg));
memset(nex, 0, sizeof(nex));
len = 1;
}
Graph() {
clear();
}
inline void add_edge(int a, int b, ll c) {
++len, tar[len] = b, cap[len] = c;
nex[len] = beg[a], beg[a] = len;
}
inline void add_pipe(int a, int b, ll c) {
add_edge(a, b, c), add_edge(b, a, 0);
} void bfs(int s)
{
memset(lev, -1, sizeof(lev));
lev[s] = 0, que.push(s);
while(!que.empty())
{
int cur = que.front(); que.pop();
for(int i = beg[cur]; i; i = nex[i])
if(cap[i] > 0 && lev[tar[i]] == -1)
{
lev[tar[i]] = lev[cur] + 1;
que.push(tar[i]);
}
}
} ll dfs(int cur, ll flo)
{
if(cur == goa) return flo;
for(int &i = ite[cur]; i; i = nex[i])
if(cap[i] > 0 && lev[cur] < lev[tar[i]])
{
ll res = dfs(tar[i], min(flo, cap[i]));
if(res)
{
cap[i] -= res;
cap[i ^ 1] += res;
return res;
}
}
return 0;
} ll dinic(int s, int t)
{
ll res, ans = 0;
goa = t;
while(true)
{
bfs(s);
if(lev[t] == -1) return ans;
memcpy(ite, beg, sizeof(beg));
while((res = dfs(s, INF)) > 0)
ans += res;
}
}
};
Graph<1024, 524288> G;
int n, m, s, t; int main()
{
while(cin >> n >> m)
{
G.clear();
s = n + n + 1, t = n + n + 2; ll sum = 0;
int u, v, a, b, c;
for(int i = 0; i != m; ++i)
{
read(u), read(v), read(a), read(b), read(c);
sum += (a + b + c) * 2;
ll x = a + b, y = b + c, z = a + c - 2 * b;
G.add_pipe(s, u, x), G.add_pipe(s, v, x);
G.add_pipe(u, t, y), G.add_pipe(v, t, y);
G.add_pipe(u, v, z), G.add_pipe(v, u, z);
}
printf("%lld\n", (sum - G.dinic(s, t)) / 2);
}
return 0;
}

题解:HDU 6598的更多相关文章

  1. [题解]hdu 1009 FatMouse' Trade(贪心基础题)

    Problem Description FatMouse prepared M pounds of cat food, ready to trade with the cats guarding th ...

  2. 2019 HDU 多校赛第二场 HDU 6598 Harmonious Army 构造最小割模型

    题意: 有n个士兵,你可以选择让它成为战士还是法师. 有m对关系,u和v 如果同时为战士那么你可以获得a的权值 如果同时为法师,你可以获得c的权值, 如果一个为战士一个是法师,你可以获得b的权值 问你 ...

  3. 题解 HDU 3698 Let the light guide us Dp + 线段树优化

    http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java ...

  4. 题解 HDU 5279 YJC plays Minecraft

    题目传送门 题目大意 给出\(n\)以及\(a_{1,2,...,n}\),表示有\(n\)个完全图,第\(i\)个完全图大小为\(a_i\),这些完全图之间第\(i\)个完全图的点\(a_i\)与\ ...

  5. 题解——HDU 4734 F(x) (数位DP)

    这道题还是关于数位DP的板子题 数位DP有一个显著的特征,就是求的东西大概率与输入关系不大,理论上一般都是数的构成规律 然后这题就是算一个\( F(A) \)的公式值,然后求\( \left [ 0 ...

  6. 题解——HDU 2089 不要62(数位DP)

    最近在学数位DP 应该是入门题吧 设\( dp[i][0/1] \)表示到第\( i \)位时,前一位是否是6的满足条件的数的个数 然后就是套路 注意\( limit \)的限制条件以及转移时候信息的 ...

  7. 题解——HDU 1848 Fibonacci again and again

    一道组合游戏的题目 SG函数的板子题 预处理出SG函数的值然后回答询问即可 代码 #include <cstdio> #include <algorithm> #include ...

  8. Hdu 6598 Harmonious Army 最小割

    N个人 每个人可以是战士/法师  M个组合 每个组合两个人 同是战士+a 同是法师+c 否则+b 对于每一个u,v,a,b,c 建(S,u,a) (u,v,a+c-2*b) (v,T,c) (S,v, ...

  9. 2019HDU多校赛第二场 H HDU 6598 Harmonious Army(最小割模型)

    参考博客https://blog.csdn.net/u013534123/article/details/97142191 #include<bits/stdc++.h> using na ...

随机推荐

  1. leetcode刷题-48旋转图像

    题目 给定一个 n × n 的二维矩阵表示一个图像. 将图像顺时针旋转 90 度. 思路 没有想到.看过解答后知道可以转置加翻转即可,且能达到最优的时间复杂度O(N^2). 实现 class Solu ...

  2. [Leetcode]148. 排序链表(归并排序)

    题目 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序. 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: ...

  3. [剑指Offer]56-数组中数字出现的次数(位运算)

    题目一 数组中只出现一次的数字 题目 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字 题解 异或. 先考虑:数组中只有一个数字只出现了一次,其他数字都出现了 ...

  4. Sql Server之ORDER BY不规则排序.如:中文月份排序

    ORDER BY CASE Month WHEN '一月' THEN 1 WHEN '二月' THEN 2 WHEN '三月' THEN 3 WHEN '四月' THEN 4 WHEN '五月' TH ...

  5. python字符串和列表小案例

    python 目录 python 一.字符串 1.给定一个字符串,利用切片将字符串反转 2.给定一个字符串,将空格替换为逗号 3.给定一个字符串,大写改为小写 4.str = '' ,li = ['l ...

  6. JVM内存结构和Java内存模型

    一.JVM 首先看一张JVM结构图(某度找的) 主要看运行时数据区,里边有方法区,堆,java虚拟机栈,本地方法栈,程序计数器.其中方法区和堆是线程共享的,也是JVM进行垃圾收集的区域,java虚拟机 ...

  7. 对比ERP解读企业资产管理EAM在电力行业应用

    对比ERP解读企业资产管理EAM在电力行业应用 .关于EAMEAM (Enterprise Asset Management)企业资产管理,是面向固定资产占企业资产主要部分的资产密集型(Capital ...

  8. SpringBoot 配置的加载

    SpringBoot 配置的加载 SpringBoot配置及环境变量的加载提供许多便利的方式,接下来一起来学习一下吧! 本章内容的源码按实战过程采用小步提交,可以按提交的节点一步一步来学习,仓库地址: ...

  9. stp域中两台switch互联接口出现两口均为root口 并且在现有stp区域中无法确定根桥设备位置;分析其原因并赋予解决办法

    stp域中两台switch互联接口出现两口均为root口 并且在现有stp区域中无法确定根桥设备位置:分析其原因并赋予解决办法 1.于上图描述了案例中当前组网环境的各交换机位置与stp状态情况  : ...

  10. Java中的lambda匿名函数使用

    Java中的lambda匿名函数使用 lambda匿名函数的使用是为了满足某些情况下需要临时定义函数,或者事先定义,需要时才使用.在python里面,lambda表达式的表达方式为:lambda 参数 ...