当前位置: 首页 > news >正文

题解:P11501 [ROIR 2019] 探险队(Day 2)

前言:这道题 dp 做法找环的部分还没有用拓扑做的,补充一下。


这道题其实很像“上司的舞会”,就是求树上最大独立集。

这里我们把每个人向他讨厌的那个人连边(发现所有点出度均为 1 1 1,所以这是一个基环树)然后求树上相邻两个结点不能同时选择时,最多能选多少个点。

如果是在普通的树上,设 f [ i ] [ 1 / 0 ] f[i][1/0] f[i][1/0] 表示结点 i i i 选或不选的最大价值,dp 即可。

基环树相当于套了一个环,考虑把环上的每一个点都当作根,跑一遍它们子树的最大点独立集(注意不能走到环上的点),然后再用“给一个环,相邻的两个元素不选,求选得的最大总和”的 dp 模板,对“基环”上的点再跑一遍 dp 把答案整合起来即可。

因为 DAG 图具有良好的 dp 结构,找环可以用拓扑排序,先把普通的点都 dp 了,拓扑结束后入度依然不为 0 0 0 的点就是环上的点。

一些实现细节见代码。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 7;
const ll inf = 1e18;int a[maxn], ind[maxn]; // ind记录入度
ll f[maxn][2]; // f[u][1/0]表示以选/不选u,其子树能得到的最大点独立集大小
bool vis[maxn]; // 记录每个点所在的连通块是否访问过int main(){ios::sync_with_stdio(false); cin.tie(0);int n;cin >> n;for(int i = 1; i <= n; i ++){cin >> a[i];if(a[i] != -1){ind[a[i]] ++;}}queue<int> q;for(int i = 1; i <= n; i ++){if(ind[i] == 0){q.push(i);}f[i][1] = 1; // 初始化dp}ll ans = 0;while(!q.empty()){int u = q.front(); q.pop();int v = a[u];if(v == -1){ans += max(f[u][0], f[u][1]); // 说明这个根节点不在环上,那么直接统计答案就好了}else{f[v][0] += max(f[u][0], f[u][1]); // 正常的树上最大独立集dpf[v][1] += f[u][0];ind[v] --;if(ind[v] == 0){q.push(v);}}}// 遍历剩下的入度不为0的结点(说明在环上)for(int i = 1; i <= n; i ++){if(ind[i] >= 1 && !vis[i]){vector<int> ring;ring.push_back(0); // 让下标从1开始int u = i;while(!vis[u]){ // 从一个点一直走,直到回到自己,就说明跑完了一整个环vis[u] = true;ring.push_back(u);u = a[u];}int len = ring.size() - 1;vector<vector<ll>> g(len + 1, {0, 0}); // g[i][1/0]表示结点i选/不选的最大答案(i在环上)// 首先钦定最后一个不选,则第一个选不选都行g[1][0] = f[ring[1]][0], g[1][1] = f[ring[1]][1];for(int j = 2; j <= len; j ++){g[j][0] = max(g[j - 1][0], g[j - 1][1]) + f[ring[j]][0];g[j][1] = g[j - 1][0] + f[ring[j]][1];}ll res1 = g[len][0];// 然后钦定第一个不选,则最后一个选不选都行g[1][0] = f[ring[1]][0], g[1][1] = -inf; // 初始化第一个选的收益为负无穷,相当于强制不选第一个for(int j = 2; j <= len; j ++){g[j][0] = max(g[j - 1][0], g[j - 1][1]) + f[ring[j]][0];g[j][1] = g[j - 1][0] + f[ring[j]][1];}ll res2 = max(g[len][0], g[len][1]);ans += max(res1, res2);}}cout << ans << '\n';return 0;
}
http://www.lryc.cn/news/573263.html

相关文章:

  • FPGA四十年创新:因仿真加速而生,AI加速而盛!
  • 【RTP】基于mediasoup的RtpPacket的H.264打包、解包和demo 2:含扩展
  • 11.RSTP快速生成树协议深度剖析:结合华为eNSP模拟器的完整实验方案
  • 为什么要BRE
  • LLM-201: OpenHands与LLM交互链路分析
  • 【基础算法】二分(二分查找 + 二分答案)
  • 华为云Flexus+DeepSeek征文|体验华为云ModelArts快速搭建Dify-LLM应用开发平台并创建b站视频总结大模型
  • Vue3 + TypeScript 中 let data: any[] = [] 与 let data = [] 的区别
  • C++ 内存分配器的作用
  • AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月21日第115弹
  • 【舞蹈】编排:如何对齐拍子并让小节倍数随BPM递减
  • 56-Oracle SQL Tuning Advisor(STA)
  • hot100——第六周
  • MagnTek MT6816-ACD 一款基于各向异性磁阻(AMR)技术的磁性角度传感器 IC
  • wordpress外贸独立站常用留言表单插件 contact form 7
  • 探索 Oracle Database 23ai 中的 SQL 功能
  • 小程序右上角○关闭事件
  • 基于深度学习的侧信道分析(DLSCA)Python实现(带测试)
  • RNN工作原理和架构
  • `teleport` 传送 API 的使用:在 Vue 3 中的最佳实践
  • Thrift 服务端的完整示例
  • 【设计模式】4.代理模式
  • 分组交换比报文交换的传输时延更低
  • PHP语法基础篇(五):流程控制
  • Occt几何内核快速入门
  • 力扣网C语言编程题:多数元素
  • OPENPPP2传输层控制算法剖析及漏洞修复对抗建议
  • 5.3 VSCode使用FFmpeg库
  • Git 使用手册:从入门到精通
  • 基于Qt的UDP主从服务器设计与实现