我们以洛谷P3387 【模板】缩点 来学习DAGdp

1.这道题的流程

  1. //伪代码
  2. for i->n if(i未被遍历) tarjan(i)
  3. 缩点()
  4. DAGdp()
  5. 完成

首先tarjan这部分应该没问题,如果想看详细的可以看我的tarjan学习记

接下来tarjan完毕,每个点属于的强连通分量也得到了,因此缩点可以进行了

这里这部分比较麻烦,下面上的代码讲的比较清楚,注释也给了。

所以现在讲讲DAGdp

我刚开始看到DAPdp……什么鬼啊?(UPD:DAG为有向无环图),然后百度,啥都没有,于是自己用类似用类似拓扑排序的方法做,发现DAGdp就是在拓扑上面弄得,那么,这就好办了

  1. void dagdp()
  2. {
  3. int i,j;
  4. queue <int> q;
  5. for(i=;i<=cnt;i++)
  6. {
  7. if(!ind[i]) //找到入度为0的点,这个点一定不会被刷新,因此满足dp无后效性
  8. {
  9. q.push(i);
  10. f[i]=money[i];
  11. }
  12. }
  13. while(!q.empty())
  14. {
  15. int t=q.front();
  16. int i,j,k;
  17. q.pop();
  18. for(i=head[t];i;i=e[i].next)
  19. {
  20. j=e[i].to;
  21. ind[j]--; //这个点的入度减一
  22. k=money[j];
  23. f[j]=max(f[t]+k,f[j]);
  24. if(!ind[j]) //如果这个点入度为0,那么这个点一定被处理完了
  25. q.push(j); //那么又可以从这个点开始做
  26. }
  27. }
  28. }

因此,这道题的程序就长这个样子

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<queue>
  6. #include<stack>
  7.  
  8. using namespace std;
  9.  
  10. int size,n,m,dt,cnt;
  11. int head[],cost[],vis[],bd[],ins[],dfn[],low[],money[];
  12. stack <int> s;
  13. int ind[],chd[],f[],ans=-,bl;
  14. struct edge{
  15. int next,to,dis;
  16. }e[],looker[]; //looker是存的边的备份
  17.  
  18. void addedge(int next,int to,int dis)
  19. {
  20. e[++size].dis=dis;
  21. e[size].to=to;
  22. e[size].next=head[next];
  23. head[next]=size;
  24. }
  25.  
  26. int pd(int a,int b) //判断边是否重复
  27. {
  28. for(int i=head[a];i;i=e[i].next)
  29. {
  30. int j=e[i].to;
  31. if(j==b) return ;
  32. }
  33. return ;
  34. }
  35.  
  36. void tarjan(int t) //tarjan操作
  37. {
  38. dfn[t]=low[t]=++bl;
  39. s.push(t);
  40. ins[t]=;
  41. int i,j;
  42. for(i=head[t];i;i=e[i].next)
  43. {
  44. j=e[i].to;
  45. if(!dfn[j])
  46. {
  47. tarjan(j);
  48. low[t]=min(low[t],low[j]);
  49. }
  50. else if(ins[j]) low[t]=min(dfn[j],low[t]);
  51. }
  52. j=;
  53. if(dfn[t]==low[t])
  54. {
  55. cnt++;
  56. while(t!=j)
  57. {
  58. j=s.top();
  59. s.pop();
  60. ins[j]=;
  61. bd[j]=cnt;
  62. }
  63. }
  64. }
  65.  
  66. void dagdp()
  67. {
  68. int i,j;
  69. queue <int> q;
  70. for(i=;i<=cnt;i++)
  71. {
  72. if(!ind[i]) //找到入度为0的点,这个点一定不会被刷新,因此满足dp无后效性
  73. {
  74. q.push(i);
  75. f[i]=money[i];
  76. }
  77. }
  78. while(!q.empty())
  79. {
  80. int t=q.front();
  81. int i,j,k;
  82. q.pop();
  83. for(i=head[t];i;i=e[i].next)
  84. {
  85. j=e[i].to;
  86. ind[j]--; //这个点的入度减一
  87. k=money[j];
  88. f[j]=max(f[t]+k,f[j]);
  89. if(!ind[j]) //如果这个点入度为0,那么这个点一定被处理完了
  90. q.push(j); //那么又可以从这个点开始做
  91. }
  92. }
  93. }
  94.  
  95. int main()
  96. {
  97. int i,j;
  98. scanf("%d %d",&n,&m);
  99. for(i=;i<=n;i++)
  100. scanf("%d",&cost[i]);
  101. for(i=;i<=m;i++)
  102. {
  103. int t1,t2;
  104. scanf("%d %d",&t1,&t2);
  105. addedge(t1,t2,);
  106. looker[i].next=t1;
  107. looker[i].to=t2;
  108. }
  109. for(i=;i<=n;i++) if(!dfn[i])tarjan(i);
  110. memset(head,,sizeof(head));
  111. size=;
  112. for(i=;i<=n;i++)
  113. {
  114. money[bd[i]]+=cost[i];
  115. }
  116. for(i=;i<=m;i++)
  117. {
  118. if(bd[looker[i].next]==bd[looker[i].to]) continue; //我 到 我自己 ?
  119. if(!pd(bd[looker[i].next],bd[looker[i].to]))
  120. {
  121. addedge(bd[looker[i].next],bd[looker[i].to],);
  122. ind[bd[looker[i].to]]++; //统计入度与出度
  123. chd[bd[looker[i].next]]++;
  124. }
  125. }
  126. dagdp();
  127. for(i=;i<=cnt;i++) ans=max(ans,f[i]); //比较每个点与当前最大值
  128. printf("%d",ans);
  129. return ;
  130. }

洛谷 P3387 【模板】缩点 DAGdp学习记的更多相关文章

  1. 洛谷P3387 【模板】缩点 题解

    背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...

  2. tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows

    缩点练习 洛谷 P3387 [模板]缩点 缩点 解题思路: 都说是模板了...先缩点把有环图转换成DAG 然后拓扑排序即可 #include <bits/stdc++.h> using n ...

  3. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  4. 洛谷——P3387 【模板】缩点

    P3387 [模板]缩点 题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点, ...

  5. 洛谷P3387 【模板】缩点

    题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只 ...

  6. 洛谷 P3387 【模板】缩点

    题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只 ...

  7. 洛谷P3375 [模板]KMP字符串匹配

    To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...

  8. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  9. 洛谷 P2656 (缩点 + DAG图上DP)

    ### 洛谷 P2656 题目链接 ### 题目大意: 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖 ...

随机推荐

  1. CentOS下查看网络状态

    查看网络状态:lsof -Pnl +M -i4 显示ipv4服务及监听端情况netstat -anp 所有监听端口及对应的进程netstat -tlnp 功能同上 网络基本命令 (1)network ...

  2. stack(单调栈) POJ 2082 Terrible Sets

    题目传送门 题意:紧贴x轴有一些挨着的矩形,给出每个矩形的长宽,问能组成的最大矩形面积为多少 分析:用堆栈来维护高度递增的矩形,遇到高度小的,弹出顶部矩形直到符合递增,顺便计算矩形面积,且将弹出的宽度 ...

  3. 修改dns访问android.com

    1.几个常用dns服务器 8.8.8.8 美国 加利福尼亚州圣克拉拉县山景市谷歌公司DNS服务器 8.8.4.4 美国 加利福尼亚州圣克拉拉县山景市谷歌公司DNS服务器 8.8.4.3 美国 加利福尼 ...

  4. 507 Perfect Number 完美数

    对于一个 正整数,如果它和除了它自身以外的所有正因子之和相等,我们称它为“完美数”.给定一个 正整数 n, 如果他是完美数,返回 True,否则返回 False示例:输入: 28输出: True解释: ...

  5. mysql索引命中规则

    转于:https://blog.csdn.net/claram/article/details/77574600 首先明确:为什么要用联合索引? 对于查询语句“SELECT E.* FROM E WH ...

  6. android动画之android:interpolator属性使用

    android动画之android:interpolator使用 Interpolator 被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速),decelerat ...

  7. wkWebView 的一些问题

    导语 WKWebView 是苹果在 WWDC 2014 上推出的新一代 webView 组件,用以替代 UIKit 中笨重难用.内存泄漏的 UIWebView.WKWebView 拥有60fps滚动刷 ...

  8. ARM 环境下使用azure powershell 从远程blob中拉去vhd 并创建虚拟机

    最近需要从指定公共访问的blob中复制vhd到自己的订阅存储账户,并使用vhd创建AZURE ARM虚拟机(非经典版),而且在portal.azure.cn中无法实现虚拟机映像创建等功能,于是自己使用 ...

  9. Java编译时根据调用该方法的类或对象所属的类决定

    class Base{     int x = 1;     static int y = 2; } class Subclass extends Base{     int x = 4;     i ...

  10. 字符串循环右移-c语言

    一个长度为len的字符串,对其循环右移n位 [期望]char str[] = "abcdefg";右移3次后,变成"efgabcd" [思路] 思路1. 如果用 ...