
【tarjan】P2272 [ZJOI2007]最大半连通子图
发布日期:2021-05-06 16:51:20
浏览次数:23
分类:精选文章
本文共 2930 字,大约阅读时间需要 9 分钟。
优化方案数计算的方法
在处理某类问题时,可能会遇到需要计算方案数的情况。为了高效解决这个问题,可以采用以下优化方法:
1. 缩点处理
首先,可以使用Tarjan算法进行缩点操作。这一步骤不会影响最终的答案结果,但可以大幅简化后续处理流程。通过缩点,可以将图中的强连通分量分解,使得后续的处理变得更加容易。
2. 拓扑排序
在完成缩点后,按照拓扑序对图进行处理。拓扑排序可以确保我们在处理节点时,总是先处理其所有依赖项,这对于动态规划等依赖性强的算法非常重要。
3. 动态规划求解方案数
由于拓扑排序已经确保了处理顺序的正确性,我们可以使用动态规划的方法来计算方案数。每个节点的状态可以基于其子节点的状态来更新,从而逐步计算出最终的方案总数。
4. 代码实现
以下是相关代码的实现说明:
#includeusing namespace std;const int maxn = 1e5 + 5;const int maxm = 1e6 + 5;int n, m, times, tot, head[maxn], dfn[maxn], low[maxn];long long mod, in[maxn];struct edge { int to, nxt;} e[maxm];void add(int x, int y) { e[++tot].nxt = head[x]; e[tot].to = y; head[x] = tot;}int col_num, top, inin[maxn], col[maxn], a[maxm], b[maxm], sta[maxn], sz[maxn];void tarjan(int x) { dfn[x] = low[x] = ++times; sta[++top] = x; inin[x] = true; for (int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if (!dfn[y]) { tarjan(y); low[x] = min(low[x], low[y]); } else if (inin[y]) { low[x] = min(low[x], dfn[y]); } } if (dfn[x] == low[x]) { int y; ++col_num; do { y = sta[--top]; inin[y] = false; col[y] = col_num; sz[col_num]++; } while (y != x); }}void build() { memset(head, 0, sizeof(head)); map st; for (int i = 1; i <= m; ++i) { long long has = (a[i] * 100000 + b[i]); if ((a[i] != b[i]) && !st[has]) { add(a[i], b[i]); st[has] = 1; } }}long long maxx, sum;void toposort() { memset(in, 0, sizeof(in)); for (int i = col_num; i >= 1; --i) { if (!dis[i]) { dis[i] = sz[i]; in[i] = 1; } for (int j = head[i]; j; j = e[j].nxt) { int k = e[j].to; if (dis[k] < dis[i] + sz[k]) { dis[k] = dis[i] + sz[k]; in[k] = in[i]; } else if (dis[k] == dis[i] + sz[k]) { in[k] = (in[k] + in[i]) % mod; } } } for (int i = 1; i <= n; ++i) { if (dis[i] > maxx) { maxx = dis[i]; sum = in[i]; } else if (dis[i] == maxx) { sum = (sum + in[i]) % mod; } } printf("%lld\n%lld\n", maxx, sum);}long long anss;void calc() { for (int i = 1; i <= n; ++i) { if (dis[i] == dis[ans]) { anss = (anss + in[i]) % mod; } }}int main() { freopen("a.in", "r", stdin); freopen("a.out", "w", stdout); scanf("%d%d%lld", &n, &m, &mod); for (int i = 1; i <= m; ++i) { scanf("%d%d", &a[i], &b[i]); add(a[i], b[i]); } for (int i = 1; i <= n; ++i) { if (!dfn[i]) { tarjan(i); } } build(); toposort(); calc(); return 0;}
5. 注意事项
在缩点完成后,需要对结果进行去重操作,否则计算出的方案数会被高估。这种方法可以有效避免重复计数,确保最终结果的准确性。
发表评论
最新留言
做的很好,不错不错
[***.243.131.199]2025年03月23日 06时43分42秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
CUDA编成:从GPU的物理体系结构到逻辑结构
2019-03-04
Java多线程3种实现方式
2019-03-04
PyQt5按键创建的几种方法
2019-03-04
Maven学习笔记(二)-仓库
2019-03-04
CentOS7报: ping: unknown host www.baidu.com
2019-03-04
Maven学习笔记(五)-使用Nexus搭建Maven私服
2019-03-04
Ubuntu15安装Redis
2019-03-04
Maven手动安装dubbo到本地仓库
2019-03-04
centos7 elasticsearch5.2.2安装kibana5.2.2
2019-03-04
centos7 elasticsearch5.2.2安装x-pack
2019-03-04
(六)多进程实现TCP服务端
2019-03-04
(Mysql 二)Linux C语言显示mysql数据库中某个表的数据
2019-03-04
JAVA单例模式
2019-03-04
AWT 窗口事件
2019-03-04
火狐浏览器无法载入配置文件
2019-03-04
面试题:说说HashMap的扩容过程?
2019-03-04
坚持阅读
2019-03-04
关于序列化和反序列化
2019-03-04
富文本的图片处理显示太大问题
2019-03-04