APIO2009 抢掠计划 Tarjan spfa/DAG-DP

题面

一道\(Tarjan\)缩点水题。因为可以反复经过节点,所以把一个联通快中的所有路口看做一个整体,缩点后直接跑\(spfa\)或者dp就好了。

在DAG上跑dp,复杂度\(O(n)\),而\(spfa\)为\(O(kn)\),所以还是优先选择dp(当然后面有\(spfa​\)的代码)

拓扑时搞DP,\(f[i]​\)表示在DAG上\(i​\)节点时,当前最大钱数,转移\(f[v]=max(f[v], f[u]+w[v])​\)

  1. #include <cstdio>
  2. #include <queue>
  3. #define MAXN 500005
  4. #define MIN(A,B) ((A)<(B)?(A):(B))
  5. #define MAX(A,B) ((A)>(B)?(A):(B))
  6. using namespace std;
  7. int n,m,sta,p;
  8. bool hav[MAXN],col_hav[MAXN];
  9. int head[MAXN],nxt[MAXN],vv[MAXN],tot;
  10. inline void add_edge(int u, int v){
  11. vv[++tot]=v;
  12. nxt[tot]=head[u];
  13. head[u]=tot;
  14. }
  15. int s[MAXN],top;
  16. bool ins[MAXN];
  17. int col[MAXN],col_cnt;
  18. int val[MAXN],col_val[MAXN];
  19. int low[MAXN],dfn[MAXN],cnt;
  20. void tarjan(int u){
  21. dfn[u]=++cnt;
  22. low[u]=cnt;
  23. s[++top]=u;
  24. ins[u]=1;
  25. for(register int i=head[u];i;i=nxt[i]){
  26. int v=vv[i];
  27. if(dfn[v]==0){
  28. tarjan(v);
  29. low[u]=MIN(low[u], low[v]);
  30. }else if(ins[v]){
  31. low[u]=MIN(low[u], dfn[v]);
  32. }
  33. }
  34. if(dfn[u]==low[u]){
  35. col[u]=++col_cnt;
  36. ins[u]=0;
  37. col_val[col_cnt]=val[u];
  38. while(s[top]!=u){
  39. col[s[top]]=col_cnt;
  40. ins[s[top]]=0;
  41. col_val[col_cnt]+=val[s[top]];
  42. top--;
  43. }
  44. top--;
  45. }
  46. }
  47. int head2[MAXN],nxt2[MAXN],vv2[MAXN],tot2;
  48. inline void add_edge2(int u, int v){
  49. vv2[++tot2]=v;
  50. nxt2[tot2]=head2[u];
  51. head2[u]=tot2;
  52. }
  53. int rdu[MAXN];
  54. inline void build(){
  55. for(register int u=1;u<=n;++u)
  56. if(dfn[u]!=0){
  57. for(register int i=head[u];i;i=nxt[i]){
  58. int v=vv[i];
  59. if(col[u]==col[v]) continue;
  60. rdu[col[v]]++;
  61. add_edge2(col[u], col[v]);
  62. }
  63. }
  64. }
  65. queue <int> q;
  66. int f[MAXN],ans=0;
  67. void dp(){
  68. q.push(col[sta]);f[col[sta]]=col_val[col[sta]];
  69. while(!q.empty()){
  70. int u=q.front();q.pop();
  71. for(register int i=head2[u];i;i=nxt2[i]){
  72. int v=vv2[i];
  73. f[v]=MAX(f[v], f[u]+col_val[v]);
  74. if((--rdu[v])==0) q.push(v);
  75. }
  76. }
  77. for(register int i=1;i<=col_cnt;++i)
  78. if(col_hav[i]) ans=MAX(f[i], ans);
  79. }
  80. int main()
  81. {
  82. scanf("%d %d", &n, &m);
  83. while(m--){
  84. int a,b;scanf("%d %d", &a, &b);
  85. add_edge(a,b);
  86. }
  87. for(register int i=1;i<=n;++i) scanf("%d", &val[i]);
  88. scanf("%d %d", &sta, &p);
  89. while(p--){
  90. int x;scanf("%d", &x);
  91. hav[x]=1;
  92. }
  93. tarjan(sta);
  94. for(register int i=1;i<=n;++i)
  95. if(hav[i]) col_hav[col[i]]=1;
  96. build();
  97. dp();
  98. printf("%d", ans);
  99. return 0;
  100. }

但是比赛时,拓扑dp写炸了,于是换成了\(spfa\),下面是\(spfa\)的写法:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <queue>
  4. #define MAXN 500005
  5. #define MAXM 500005
  6. #define MIN(A,B) ((A)<(B)?(A):(B))
  7. #define MAX(A,B) ((A)>(B)?(A):(B))
  8. using namespace std;
  9. int n,m,val[MAXM],sta,p;
  10. int head[MAXM],nxt[MAXM],vv[MAXM],tot;
  11. inline void add_edge(int u, int v){
  12. vv[++tot]=v;
  13. nxt[tot]=head[u];
  14. head[u]=tot;
  15. }
  16. int low[MAXN],dfn[MAXN],cnt;
  17. int s[MAXN],top;
  18. int col[MAXN],col_cnt;
  19. long long col_val[MAXN];
  20. bool ins[MAXN];
  21. bool col_can[MAXN];
  22. bool hav[MAXN];
  23. bool col_hav[MAXN];
  24. void tarjan(int u){
  25. ins[u]=1;
  26. dfn[u]=low[u]=++cnt;
  27. s[++top]=u;
  28. for(register int i=head[u];i;i=nxt[i]){
  29. int v=vv[i];
  30. if(dfn[v]==0){
  31. tarjan(v);
  32. low[u]=MIN(low[u], low[v]);
  33. }else if(ins[v]){
  34. low[u]=MIN(low[u], dfn[v]);
  35. }
  36. }
  37. if(low[u]==dfn[u]){
  38. ins[u]=0;
  39. col[u]=++col_cnt;
  40. col_val[col_cnt]=val[u];
  41. if(hav[u]) col_hav[col_cnt]=1;
  42. while(s[top]!=u){
  43. col[s[top]]=col_cnt;
  44. ins[s[top]]=0;
  45. col_val[col_cnt]+=val[s[top]];
  46. if(hav[s[top]]) col_hav[col_cnt]=1;
  47. top--;
  48. }
  49. top--;
  50. }
  51. }
  52. int du[MAXN];
  53. int head2[MAXN],nxt2[MAXM],vv2[MAXM],tot2;
  54. inline void add_edge2(int u, int v){
  55. vv2[++tot2]=v;
  56. nxt2[tot2]=head2[u];
  57. head2[u]=tot2;
  58. }
  59. void build(){
  60. for(register int u=1;u<=n;++u)
  61. for(register int i=head[u];i;i=nxt[i]){
  62. int v=vv[i];
  63. if(col[u]==col[v]) continue;
  64. add_edge2(col[u], col[v]);
  65. du[col[v]]++;
  66. }
  67. }
  68. queue <int> q;
  69. long long f[MAXN];
  70. long long ans;
  71. bool inq[MAXN];
  72. void spfa(){
  73. f[col[sta]]=col_val[col[sta]];
  74. q.push(col[sta]);
  75. while(!q.empty()){
  76. int u=q.front();q.pop();
  77. inq[u]=0;
  78. for(register int i=head2[u];i;i=nxt2[i]){
  79. int v=vv2[i];
  80. if(f[v]<f[u]+col_val[v]){
  81. f[v]=f[u]+col_val[v];
  82. if(!inq[v]) inq[v]=1,q.push(v);
  83. }
  84. }
  85. }
  86. for(register int i=1;i<=col_cnt;++i)
  87. if(col_hav[i]) ans=MAX(ans, f[i]);
  88. }
  89. int main()
  90. {
  91. scanf("%d %d", &n, &m);
  92. while(m--){
  93. int a,b;scanf("%d %d", &a, &b);
  94. add_edge(a,b);
  95. }
  96. for(register int i=1;i<=n;++i)
  97. scanf("%d", &val[i]);
  98. scanf("%d %d", &sta, &p);
  99. while(p--){
  100. int x;scanf("%d", &x);
  101. hav[x]=1;
  102. }
  103. tarjan(sta);
  104. build();
  105. spfa();
  106. printf("%lld", ans);
  107. return 0;
  108. }

APIO2009 抢掠计划 Tarjan DAG-DP的更多相关文章

  1. 洛谷 P3627 [APIO2009]抢掠计划 Tarjan缩点+Spfa求最长路

    题目地址:https://www.luogu.com.cn/problem/P3627 第一次寒假训练的结测题,思路本身不难,但对于我这个码力蒟蒻来说实现难度不小-考试时肛了将近两个半小时才刚肛出来. ...

  2. [APIO2009]抢掠计划 tarjan缩点+spfa BZOJ1179

    题目描述 Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设 ...

  3. [APIO2009]抢掠计划 ($Tarjan$,最长路)

    题目链接 Solution 裸题诶... 直接 \(Tarjan\) 缩点+ \(SPFA\) 最长路即可. 不过在洛谷上莫名被卡... RE两个点... Code #include<bits/ ...

  4. [luogu3627 APIO2009] 抢掠计划 (tarjan缩点+spfa最长路)

    传送门 Description Input 第一行包含两个整数 N.M.N 表示路口的个数,M 表示道路条数.接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表 ...

  5. P3627 [APIO2009]抢掠计划

    P3627 [APIO2009]抢掠计划 Tarjan缩点+最短(最长)路 显然的缩点...... 在缩点时,顺便维护每个强连通分量的总权值 缩完点按照惯例建个新图 然后跑一遍spfa最长路,枚举每个 ...

  6. [APIO2009]抢掠计划(Tarjan,SPFA)

    [APIO2009]抢掠计划 题目描述 Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是, ...

  7. 题解 P3627 【[APIO2009]抢掠计划】

    咕了四个小时整整一晚上 P3627 [APIO2009] 抢掠计划(https://www.luogu.org/problemnew/show/P3627) 不难看出答案即为该有向图的最长链长度(允许 ...

  8. 【洛谷P3627】[APIO2009]抢掠计划

    抢掠计划 题目链接 比较水的缩点模板题,Tarjan缩点,重新建图,记录联通块的钱数.是否有酒吧 DAG上记忆化搜索即可 #include<iostream> #include<cs ...

  9. Tarjan缩点+Spfa最长路【p3627】[APIO2009] 抢掠计划

    Description Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri ...

随机推荐

  1. jacascript 基础数据类型(一)

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! 数据类型有 number.boolean.string.object.null.undefined; un ...

  2. Android蓝牙遥控器APP关键代码 guihub项目

    package com.car.demo; import java.io.IOException; import java.io.OutputStream; import java.util.UUID ...

  3. leetcode-55. Jump Game · Array

    题面 这个题面挺简单的,不难理解.给定非负数组,每一个元素都可以看作是一个格子.其中每一个元素值都代表当前可跳跃的格子数,判断是否可以到达最后的格子. 样例 Input: [2,3,1,1,4] Ou ...

  4. elementUI .native修饰符

    用第三方组件或者UI框架会自带自身封装的事件,如keyup等,会覆盖原生的组件而无法起效果 .native 修饰符就是用来注册元素的原生事件而不是组件自定义事件的 如elementUI的:<el ...

  5. nginx的so_keepalive和timeout相关小计

    KeepAlive 这里的keepalive是TCP的探活机制: [root@ ~]# sysctl -a |grep tcp_keepalive net.ipv4.tcp_keepalive_tim ...

  6. impala 下的SQL函数

    #把时间转化成时间戳select cast('1966-07-30' as timestamp);select cast('1985-09-25 17:45:30.005' as timestamp) ...

  7. 浅谈JAVA继承关系中的构造函数

    话不多说直接上例子,我的例子中定义了两个类,TheSon和TheFather,TheSon继承了TheFather,如图: TheSon类的定义: ​ TheFather类的定义: 当我们初始化The ...

  8. java利用MultipartRequest的getFileName方法不能得到原文件名问题

    想利用MultipartRequest的getFileName方法来一次获取多个上传的文件名字时,得到的不是文件的名字,而是 input 的name属性 最后找到了答案,解决方法,参照http://s ...

  9. Computer Vision_33_SIFT:Evaluation of Interest Point Detectors——2000

    此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...

  10. 连接mongodb服务器

    连接mongodb有几种方法 一种是使用mongodb编译时生成的客户端进行连接,就是我们之前介绍过的mongo客户端 另一种是使用各种驱动进行连接 这次使用mongo客户端进行连接,之前我们启动了一 ...