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

P3387 【模板】缩点

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 10,inf = 0x3f3f3f3f;// g: 原图的邻接表, e: 缩点后新图的邻接表
vector<int> g[N],e[N];// Tarjan算法相关
int dfn[N],low[N],id;    // dfn:深度优先序, low:能回溯到的最小dfn, id:时间戳计数器
int q[N],top,inq[N];     // q:模拟栈, top:栈顶, inq:标记节点是否在栈中
int n,m;// 缩点相关
int scc[N],sccnt;        // scc[i]:节点i所属的SCC编号, sccnt:SCC计数器
int sccval[N];           // sccval[i]:第i个SCC的总权值// 拓扑排序相关
ll a[N],f[N];            // a[i]:原节点权值, f[i]:以SCC i结尾的最大路径和
int rd[N];               // rd[i]:SCC i的入度// Tarjan算法求强连通分量
void tarjan(int x)
{dfn[x] = low[x] = ++id;    // 初始化当前节点的dfn和lowq[++top] = x;              // 节点入栈inq[x] = 1;                // 标记节点在栈中// 遍历所有邻接节点for(int i = 0; i < g[x].size(); i++){int y = g[x][i];if(dfn[y] == 0){        // 树边:y未被访问
            tarjan(y);low[x] = min(low[x],low[y]);  // 回溯时更新low值
        }else if(inq[y]) low[x] = min(low[x],dfn[y]);  // 回边:y在栈中
    }// 找到SCC的根节点if(low[x] == dfn[x]){sccnt++;while(1){int y = q[top--];     // 弹出栈顶节点inq[y] = 0;           // 标记不在栈中scc[y] = sccnt;       // 记录节点所属SCCsccval[sccnt] += a[y]; // 累加SCC权值if(x == y) break;     // 弹出直到遇到根节点x
        }}
}// 拓扑排序求DAG最长路径,注意拓扑排序中用的是新图e,而非g 
void topsort()
{queue<int> q;ll ans = 0;// 初始化:所有入度为0的SCC入队for(int i = 1; i <= sccnt; i++){    f[i] = sccval[i];         // 初始值为SCC自身权值if(rd[i] == 0) q.push(i); // 入度为0的入队
    }// 拓扑排序while(q.size()){int x = q.front(); q.pop();// 遍历x的所有出边for(int i = 0; i < e[x].size(); i++){int y = e[x][i];rd[y]--;  // 入度减1// 状态转移:f[y] = max(f[y], f[x] + sccval[y])f[y] = max(f[y],f[x] + sccval[y]);ans = max(ans,f[y]);  // 更新答案if(rd[y] == 0) q.push(y);  // 入度为0时入队
        }}// 确保找到最大值(处理没有入度的孤立SCC)for(int i = 1; i <= sccnt; i++) ans = max(ans,f[i]);cout << ans;
}int main()
{// 输入处理cin >> n >> m;for(int i = 1; i <= n; i++) cin >> a[i];  // 读入点权for(int i = 1; i <= m; i++){int x,y; cin >> x >> y;g[x].push_back(y);  // 构建原图
    }// 步骤1: Tarjan算法求所有强连通分量for(int i = 1; i <= n; i++){if(dfn[i] == 0) tarjan(i);  // 对每个未访问节点执行Tarjan
    }// 步骤2: 构建缩点后的新图(DAG)for(int i = 1; i <= n; i++){for(int j = 0; j < g[i].size(); j++){int y = g[i][j];if(scc[i] != scc[y]){  // 不同SCC之间的边e[scc[i]].push_back(scc[y]);  // 添加新图的边rd[scc[y]]++;                 // 目标SCC入度加1
            }}}// 步骤3: 拓扑排序求最长路径
    topsort();return 0;
}

 

http://www.jsqmd.com/news/551050/

相关文章:

  • 告别Conda激活玄学:从`conda init`原理到一键修复脚本(Win/Mac/Linux通用)
  • 提升arduino开发效率:用快马平台一键生成常用工具模块代码
  • VisualCppRedist AIO:一站式解决Windows系统运行库依赖难题
  • Stable-Diffusion-V1-5 保姆级部署:Node.js环境配置与自动化脚本编写
  • 零基础也能挖洞赚钱?SRC漏洞挖掘从入门到精通,附全套工具包+学习路线!
  • 口碑好的企业号码认证服务商有哪些?实现手机座机显示公司名 - 企业服务推荐
  • 告别top和netstat:用sysdig一个命令搞定Linux系统监控(含Docker容器)
  • OpenClaw安全防护指南:Qwen3-32B操作权限管控与敏感数据隔离
  • md2pptx:如何通过Markdown实现演示文稿的高效制作与自动化管理
  • STM32CubeMX配置Qwen-Image-Edit-F2P物联网终端应用
  • 避开FPGA时序分析盲区:除了Clock和Data,别忘了用Set_Data_Check给你的控制信号也上个‘闹钟’
  • Docker Desktop+WSL2自定义安装路径实战指南
  • 突破显卡限制:OptiScaler实现全平台AI超分辨率技术自由切换
  • 凤凰娴《原元源》:在剧变中重建内心秩序感
  • 写不出来、改不完?GradPaper 帮你终结论文内耗
  • 明略科技公布上市后首次年报:营收14亿 经调整净利4204万
  • Qt 6.5 Qml地图开发避坑指南:从零搞定Map组件、OSM插件与海量点渲染
  • 避坑!Eclipse汉化后插件不兼容?试试这个无损切换方案
  • 别再只用StarterKit了!解锁Tiptap在Vue3中的5个高级玩法与性能优化技巧
  • Qwen3.5-4B-Claude-Opus参数详解:Temperature/Top-P/max_tokens调优实战手册
  • 基于SpringBoot + Vue的新农村信息平台建设(角色:企业村民村委会管理员)
  • 440MHz VGA电路设计实战:如何用PIN管实现稳定增益控制(附仿真数据)
  • 戴森球计划蓝图宝典:从新手到高手的完整工厂建设指南
  • LivePortrait:基于缝纫与重定向控制的高效人像动画生成系统
  • 春联生成模型互联网公开API设计与安全实践
  • 别再只玩ChatGPT了!用CosyVoice-300M + Xinference给你的AI数字人配上专属声音(附完整项目代码)
  • Linux笔记本风扇智能控制:NBFC从入门到精通
  • 从BOLD信号到MNI空间:用Python复现fMRI预处理全流程(DPABI/SPM12对比)
  • 多智能体金融决策系统深度解析:TradingAgents-CN的技术架构与实践价值
  • 别再只会用pwelch了!用MATLAB手把手对比BT法、周期图法、Bartlett和Welch法,选对方法才准