P10974 换根 dp 解题报告

news/2024/11/27 19:35:26/文章来源:https://www.cnblogs.com/Brilliant11001/p/18572953

题目传送门

题目大意:

给定一颗无根树,有一个节点是源点,度数为 \(1\) 的点是汇点,树上的边有最大流量。除源点和汇点外,其它点不储存水,即流入该点的水量之和等于从该点流出的水量之和。整个水系的流量定义为原点单位时间内能发出的水量

现在需要求出:在流量不超过最大流量的前提下,选取哪个点作为源点,整个水系的流量最大,输出最大值。

思路:

朴素的想法是枚举某个点作为源点,然后做树形 dp,设 \(f_u\) 表示从点 \(u\) 往下流向子树的最大流量,不难得出状态转移方程:

\[f_u = \sum\limits_{j\in Son(u)}\begin{cases}\min(w_i, f_j) & \deg_j > 1\\w_i & \deg_j = 1\end{cases} \]

对于每个点都这样做一遍,取 \(\max\),时间复杂度 \(O(n^2)\)

暴力 \(\texttt{Code:}\)

#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 200010, M = 400010;
typedef long long ll;
int T, n;
int h[N], e[M], ne[M], w[M], idx;
int deg[N];
ll f[N];void init() {for(int i = 1; i <= n; i++)deg[i] = 0, h[i] = -1;
}inline void add(int a, int b, int c) {e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}void dfs(int u, int fa) {f[u] = 0;for(int i = h[u]; ~i; i = ne[i]) {int j = e[i];if(j == fa) continue;dfs(j, u);if(deg[j] == 1) f[u] += w[i];f[u] += min(f[j], (ll)w[i]);}
}void solve() {scanf("%d", &n);init();for(int a, b, c, i = 1; i < n; i++) {scanf("%d%d%d", &a, &b, &c);add(a, b, c), add(b, a, c);deg[a]++, deg[b]++;}ll ans = 0;for(int i = 1; i <= n; i++) dfs(i, -1), ans = max(ans, f[i]);printf("%lld\n", ans);
}int main() {scanf("%d", &T);while(T--) {solve();}return 0;
}

因为这个题是一个无根树,而我们又要枚举根节点,所以不难想到用换根 dp 来代替源点的枚举。

所以考虑用换根 dp 来优化。

来回顾一下换根 dp 的基本思路:

  1. 第一次 dfs,任选一个点为根进行方才的树形 dp;
  2. 第二次 dfs,从相同的根出发,再扫描一遍从父节点向子结点更新信息,这里多半会用到剔除贡献的问题,要么记最大/次大值和具体从哪个点更新(这个主要用于最大/最小的不满足可减性的信息),要么从第一遍 dfs 的信息更新处倒推(这个一般用于满足可减性的信息)。

对应到这个题上就是思考子节点流向父节点的信息怎么计算。

先画个图:

这里 \(g_u\) 表示 \(u\) 为源点的最大流量。

这道题的信息显然具有可减性。

如图,我们可以考虑先去掉 \(j\) 子树对 \(g_u\) 的贡献得到以 \(u\) 为源点的其他贡献,然后这一部分实际就是从 \(j\) 往上流的最大流量,直接和 \(f_j\) 相加就得到了 \(g_j\)

但是这里有个魔鬼细节,需要考虑节点的度数,因为度数为 \(1\) 的点在第一遍 dfs 时是直接加上的 \(w_i\),所以在去掉贡献的时候需要判一下。父节点也基本同理。

那么这道题就结束了,时间复杂度 \(O(n)\)

\(\texttt{AC Code:}\)

#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 200010, M = 400010;
typedef long long ll;
int T, n;
int h[N], e[M], ne[M], w[M], idx;
int deg[N];
ll f[N], g[N];void init() {for(int i = 1; i <= n; i++)deg[i] = 0, h[i] = -1;
}inline void add(int a, int b, int c) {e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}void dfs(int u, int fa) {f[u] = 0;for(int i = h[u]; ~i; i = ne[i]) {int j = e[i];if(j == fa) continue;dfs(j, u);if(deg[j] == 1) f[u] += w[i];else f[u] += min(f[j], (ll)w[i]);}
}void dfs2(int u, int fa) {for(int i = h[u]; ~i; i = ne[i]) {int j = e[i];if(j == fa) continue;g[j] = f[j];if(deg[u] == 1) g[j] += w[i];else if(deg[j] == 1) g[j] += min((ll)w[i], g[u] - (ll)w[i]);else g[j] += min((ll)w[i], g[u] - min((ll)w[i], f[j]));dfs2(j, u);}
}void solve() {scanf("%d", &n);init();for(int a, b, c, i = 1; i < n; i++) {scanf("%d%d%d", &a, &b, &c);add(a, b, c), add(b, a, c);deg[a]++, deg[b]++;}dfs(1, -1);g[1] = f[1];dfs2(1, -1);ll ans = 0;for(int i = 1; i <= n; i++)ans = max(ans, g[i]);printf("%lld\n", ans);
}int main() {scanf("%d", &T);while(T--) {solve();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/842448.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CH592/CH585工具更新说明_USB篇

①打开USB更新工具 ②保证芯片没有供电以及没有GPIO灌电的前提下,将PB22接到低电平GND上(进入BootLoader),再插入USB线供电,之后点击软件中的Search Device即可搜索到设备 ③点击Download下载程序即可 ④烧录成功样例

H5-6 列表标签 有序列表

1、有序标签有序列表是一列项目,列表项目使用数学进行标记。有序列表始于<ol>标签。每个列表始于<li>标签。 <ol><li></li><li></li></ol> 2、type属性: <ol>的属性type拥有的选项1表示列表项目用数字标号(1,2,…

rust学习十二、测试

测试从来不是一件简单的事情,我本人深有体会! 书本作者引用了很重要的话:软件测试是证明 bug 存在的有效方法,而证明其不存在时则显得令人绝望的不足 (Edsger W. Dijkstra 在其 1972 年的文章【谦卑的程序员】(“The Humble Programmer”)) 注:Edsger W. Dijkstra在1…

NOIP2024加赛8

如此状态,如何NOIP状态很不好,恼了。虚拟机太卡了,根本交不上去。 flandre 发现选取的肯定是从大到小排序后的一个后缀,然后就做完了,时间复杂度\(O(n\log n)\)。点此查看代码 #include<bits/stdc++.h> using namespace std; #define rep(i,s,t,p) for(int i = s;i …

根据条件显示不同背景色

1. 概述1.1 问题描述 在 FineReport 中制作报表时,经常遇到在满足一定条件下「单元格/行/列」需要显示为不同的背景色,那么该如何实现呢? 1.2 解决思路 可以通过添加「条件属性>背景」来实现。 设置「当前格子/当前行/当前列」的原理一样,本文以「当前格子」和「当前行」…

Linux下打包Qt应用程序

linux下打包应用程序 非常复杂 接下来一步一步实现 第一步:下载linuxdeployqt程序 我已经保存在了百度网盘,记住qt5用老一些的版本 第二步:下载好后重命名为linuxdeployqt好用一点 然后将其移动到/usr/local/bin目录下 并且授权 记住 一定要授权 检查是否成功 sudo lin…

Linux ubuntu命令行安装图形界面

前言全局说明服务器上默认是没有图形界面的,但是需要时,只能单独安装。或者安装时没有装图形界面,后期又用到。一、说明 环境: Ubuntu 18.04.6 LTS (Linux qt-vm 5.4.0-150-generic #167~18.04.1-Ubuntu SMP Wed May 24 00:51:42 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux)…

H5-6 文本

<em>  定义着重文字<b>   定义粗体文本<i>   定义斜体字<strong> 定义加重语气 <del>  定义删除字<span> 元素没有特定的含义  常用文本标签和段落是不同的,段落代表一段文本,而文本标签一般表示文本词汇 可以嵌套在&l…

app实战运用

一、打开模拟器 二、cmd中打开dos命令 adb connect 127.0.0.1:62001 三、安装测试包 adb install D:\app\baiduyuedu_3760.apk 四、打开appium五、( 定位元素没有xpath的就删除原有uiautomatorviewer.bat,替换成新的) 开始定位,定位插件案例1: from appium import…

WebRTC 创建者刚加入了 OpenAI,他是如何思考语音 AI 的未来?

WebRTC 的早期创建者之一,Fixie.ai 联合创始人兼 CTO Justin Uberti 近日宣布加入 OpenAI,领导实时 AI (Real-Time AI)项目的开发。Uberti 在 2011 年于 Google 参与创建并领导了 WebRTC 项目,并推动其成为 W3C 和 IETF 标准。从最早参与 AOL Instant Messenger(AIM)开始…

win10 查看 特定网络 详细信息

使用以下命令查看某个网络的详细信息(替换<NetworkName>为实际的网络名称):TEXTnetsh wlan show profile name="<NetworkName>" key=clear

#20222309 2024-2025-1 《网络与系统攻防技术》实验五实验报告

1.实验内容 (1)从www.besti.edu.cn、baidu.com、sina.com.cn中选择一个DNS域名进行查询,获取如下信息: DNS注册人及联系方式 该域名对应IP地址 IP地址注册人及联系方式 IP地址所在国家、城市和具体地理位置 PS:使用whois、dig、nslookup、traceroute、以及各类在线和离线工…