热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HihoCoder1398:最大权闭合子图问题解析

本文详细探讨了HihoCoder平台上的1398号问题——最大权闭合子图的求解方法。通过具体实例,深入分析了最大权闭合子图的概念及其算法实现。

在HihoCoder平台上的1398号问题中,我们面临的是一个经典的最大权闭合子图问题。该问题的核心在于从给定的图中找到一个子图,这个子图需要满足其内部的所有节点之间的边都在子图内部,同时这个子图的所有节点权重之和达到最大。

为了更好地理解这个问题,我们首先需要了解闭合子图的概念。简而言之,如果从图的一个子集中任选一点出发,沿着任何一条路径走,终点仍然在这个子集中,那么这个子集就是一个闭合子图。

最大权闭合子图是指,在一个赋予权重的图中,寻找一个闭合子图,使得这个子图中所有节点的权重总和最大。解决这一问题的关键在于构建一个网络流模型,并利用最大流算法来求解。

具体的步骤如下:

  1. 构造一个超级源点S和一个超级汇点T,用于连接图中的其他节点。
  2. 对于所有权重为正的节点,将其与超级源点S相连,边的容量设置为节点的权重值。
  3. 对于所有权重为负的节点,将其与超级汇点T相连,边的容量设置为节点权重的绝对值。
  4. 对于图中原有的边,保持不变,但将每条边的容量设为无穷大,以确保这些边不会成为瓶颈。
  5. 计算从S到T的最大流(等价于最小割),最终的最大权闭合子图的权重即为所有正权重节点的权重总和减去最大流的值。

以下是解决此问题的C++代码示例:

#include 
#define N 100005
#define INF 0x7f7f7f7f
using namespace std;
int n, m, s, t, c, sum;
int head[N], cur[N], deep[N];
struct Edge {
int to, next, w;
};
Edge e[2 * N];
void add(int x, int y, int z) {
e[c].next = head[x]; e[c].w = z; e[c].to = y; head[x] = ++c;
}
bool bfs(int s, int t) {
memset(deep, 0, sizeof(deep));
deep[s] = 1;
queue q;
q.push(s);
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = head[x]; i != -1; i = e[i].next) {
int nex = e[i].to;
if (!deep[nex] && e[i].w > 0) {
deep[nex] = deep[x] + 1;
q.push(nex);
}
}
}
return deep[t];
}
int dfs(int x, int t, int maxflow) {
if (x == t) return maxflow;
int ans = 0;
for (int i = cur[x]; i != -1; i = e[i].next) {
int nex = e[i].to;
if (e[i].w <= 0 || ans >= maxflow || deep[nex] != deep[x] + 1) continue;
cur[x] = i;
int k = dfs(nex, t, min(e[i].w, maxflow - ans));
e[i].w -= k;
e[i ^ 1].w += k;
ans += k;
}
if (ans == 0) deep[x] = -2;
return ans;
}
int Dinic(int s, int t) {
int ans = 0;
while (bfs(s, t)) {
memcpy(cur, head, sizeof(head));
ans += dfs(s, t, INF);
}
return ans;
}
int main() {
while (~scanf("%d%d", &n, &m)) {
int x, y, z;
s = 0;
t = n + m + 1;
c = 0;
sum = 0;
memset(head, -1, sizeof(head));
for (int i = 1; i <= m; i++) {
scanf("%d", &x);
add(n + i, t, x);
add(t, n + i, 0);
}
for (int i = 1; i <= n; i++) {
scanf("%d%d", &x, &y);
sum += x;
add(s, i, x);
add(i, s, 0);
for (int j = 1; j <= y; j++) {
scanf("%d", &z);
add(i, n + z, INF);
add(n + z, i, 0);
}
}
printf("%d\n", sum - Dinic(s, t));
}
}

推荐阅读
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • 线段树详解与实现
    本文详细介绍了线段树的基本概念及其在编程竞赛中的应用,并提供了一个具体的线段树实现代码示例。 ... [详细]
  • 网络流24题——试题库问题
    题目描述:假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算 ... [详细]
  • hlg_oj_1116_选美大赛这题是最长子序列,然后再求出路径就可以了。开始写的比较乱,用数组什么的,后来用了指针就好办了。现在把代码贴 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 本问题涉及在给定的无向图中寻找一个至少包含三个节点的环,该环上的节点不重复,并且环上所有边的长度之和最小。目标是找到并输出这个最小环的具体方案。 ... [详细]
  • 本文详细介绍了如何在循环双链表的指定位置插入新元素的方法,包括必要的步骤和代码示例。 ... [详细]
  • LeetCode 102 - 二叉树层次遍历详解
    本文详细解析了LeetCode第102题——二叉树的层次遍历问题,提供了C++语言的实现代码,并对算法的核心思想和具体步骤进行了深入讲解。 ... [详细]
  • 编码unicode解决了语言不通的问题.但是.unicode又有一个新问题.由于unicode是万国码.把所有国家的文字都编进去了.这就导致一个unicode占用的空间会很大.原来 ... [详细]
  • 本文详细介绍了在Luat OS中如何实现C与Lua的混合编程,包括在C环境中运行Lua脚本、封装可被Lua调用的C语言库,以及C与Lua之间的数据交互方法。 ... [详细]
  • 本题要求计算一组正整数的最小公倍数(LCM)。输入包括多组测试数据,每组数据首先给出一个正整数n,随后是n个正整数。 ... [详细]
  • c语言二元插值,二维线性插值c语言
    c语言二元插值,二维线性插值c语言 ... [详细]
  • 本文档介绍了如何使用ESP32开发板在STA模式下实现与TCP服务器的通信,包括环境搭建、代码解析及实验步骤。 ... [详细]
  • C++11 新特性解析:Lambda 表达式与函数包装器
    本文深入探讨 C++11 中引入的 Lambda 表达式及其应用,以及如何利用函数包装器(Function Wrappers)实现更灵活的编程模式。通过具体示例,展示这些特性在实际开发中的优势。 ... [详细]
  • 使用QT构建基础串口辅助工具
    本文详细介绍了如何利用QT框架创建一个简易的串口助手应用程序,包括项目的建立、界面设计与编程实现、运行测试以及最终的应用程序打包。 ... [详细]
author-avatar
1074017584_789ded
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有