题目描述

  • 输入描述 Input Description
    第一行包含两个整数N、M。N 表示路口的个数,M 表示道路条数。接下来
    M 行,每行两个整数,这两个整数都在1 到N 之间,第i+1 行的两个整数表示第
    i 条道路的起点和终点的路口编号。接下来N 行,每行一个整数,按顺序表示每
    个路口处的ATM 机中的钱数。接下来一行包含两个整数S、P,S 表示市中心的
    编号,也就是出发的路口。P 表示酒吧数目。接下来的一行中有P 个整数,表示
    P 个有酒吧的路口的编号。

  • 输出描述 Output Description
    输出一个整数,表示Banditji 从市中心开始到某个酒吧结束所能抢劫的最多
    的现金总数。

  • 样例输入 Sample Input
    6 7
    1 2
    2 3
    3 5
    2 4
    4 1
    2 6
    6 5
    10
    12
    8
    16
    1 5
    1 4
    4 3 5 6

  • 样例输出 Sample Output
    47

  • 数据范围及提示 Data Size & Hint
    50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM
    机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心
    沿着Siruseri 的单向的道路到达其中的至少一个酒吧。

题解

  • 题意还是比较裸的,在环上的ATM机是一定都要抢的。首先是求强连通分量缩点,然后从起点即市中心开始spfa最长路或者DP,目的是求出最终停在每个强连通分量时所抢得的总钱数;然后读入所有酒吧,把有酒吧的强连通分量作为终点,枚举一下取钱数的最大值即可。

  • 然而数据规模使得递归的tarjan算法被卡住了,所以要手动改成非递归。

  • 首先用一个大栈(可以理解成系统栈的替代品,区分递归tarjan用到的小栈)保存当前正在tarjan的点。设当前正在tarjan点x,则先把x入大栈,同时入小栈,标记x的dfn和low的值,并作出相应标记表示x已经入了小栈(就像递归tarjan一样);

  • 其次,开始非递归主过程:
    大栈非空时,从栈顶取出一个元素t,但不要弹栈;
    访问t所有出边指向的结点a,若dfn[a]等于0,就把a压入大栈,相当于递归tarjan中的递归调用tarjan(a),然后break掉,进入下文中的“然后”,因为递归tarjan中此时low(a)的值会在递归过程中算出,非递归tarjan中low(a)的值还不知道;
    若dfn[a]不等于0,不急,先什么也不干,下文中“然后”会处理;

  • 然后,t所有出边都已被遍历,这时,判断t是否是大栈的栈顶;
    如果是,则说明t没有进入任何递归过程,即t所有出边指向的点都已经被tarjan完了,这时应该确定low[t]的值;
    访问t所有出边指向的结点a,若dfn[a]>>dfn[t],说明上文“其次”中访问a时a的dfn是0,所以执行递归tarjan中调用完tarjan(a)之后的操作——low[t] = min(low[t], low[a]);
    若dfn[a]<dfn[t],说明上文“其次”中访问a时a的dfn不是0,所以执行递归tarjan中dfn[a]!=!=0之后的操作——若a在小栈中则low[t] = min(low[t], dfn[a]);
    这样,我们确定了low[t]的值;
    如果此时dfn[t]====low[t],则从小栈里取出这个强连通分量,过程和递归tarjan完全相同,故不再赘述,此后才可以在大栈中弹掉t,因为t所属的强连通分量被算出来以后,tarjan(t)才真正结束,t才可以从大栈里取出;
    如果t不是大栈的栈顶,则回到上文中的“其次”,相当于递归调用t的出边指向的某个终点;

  • 最后,“其次”时发现大栈为空,算法结束。

  • Code

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#define nil 0
#define N 500005
using namespace std;
int n, m, csh[N], S, P, f[N];//题目中的变量,csh代表缩点前每个点有多少钱,f[i]是第i个强连通分量为终点能抢多少钱
int u[N << 2], v[N << 2], nxt[N << 2], pnt[N], e;//存原图用的邻接表
int dfn[N], low[N], isin[N], hcash[N], tot, indx;//tarjan算法,hcash[i]表示第i个强连通分量一共有多少钱
bool instack[N], vis[N];//instack存是否在小栈中,vis是spfa用的
int Sta[N], stop;//小栈
vector <int> g[N];//存缩点后的新图用的vector
stack <int> s;//大栈
void add(int a, int b)//向原图中加边
{u[++e] = a; v[e] = b;nxt[e] = pnt[a]; pnt[a] = e;
}
/*void tarjan(int k)//递归tarjan
{dfn[k] = low[k] = ++indx;instack[k] = true;Sta[++stop] = k;for(int j = pnt[k]; j != nil; j = nxt[j]){if(dfn[v[j]] == nil){tarjan(v[j]);low[k] = min(low[k], low[v[j]]);}else{if(instack[v[j]] && dfn[v[j]] < low[k]){low[k] = dfn[v[j]];}}}if(dfn[k] == low[k]){++tot;int j;do{j = Sta[stop--];instack[j] = false;isin[j] = tot;hcash[tot] += csh[j];} while(j != k);}
}*/
void tarjan(int x)//非递归tarjan
{s.push(x);dfn[x] = low[x] = ++indx;Sta[++stop] = x;instack[x] = true;while(!s.empty()){int t = s.top();for(int i = pnt[t]; i != nil; i = nxt[i])//这里可以开一个和ISAP最大流相似的当前弧优化,不过似乎用处不大 {if(dfn[v[i]] == 0)//如果未访问,则压栈,准备访问 {dfn[v[i]] = low[v[i]] = ++indx;Sta[++stop] = v[i]; instack[v[i]] = true;s.push(v[i]);break;//一定要break,意思是立即递归调用tarjan(a) }}if(t == s.top()){for(int i = pnt[t]; i != nil; i = nxt[i]){if(dfn[v[i]] > dfn[t]) low[t] = min(low[t], low[v[i]]);//这句对应递归tarjan中的if(dfn[v[j]] != 0)的情况 else if(instack[v[i]]) low[t] = min(low[t], dfn[v[i]]);}if(dfn[t] == low[t]){++tot;int j;do{j = Sta[stop--];instack[j] = false;isin[j] = tot;hcash[tot] += csh[j];} while(j != t);}s.pop();}}
}
void init()
{int a, b;scanf("%d%d", &n, &m);for(int i = 1; i <= m; ++i){scanf("%d%d", &a, &b);add(a, b);}for(int i = 1; i <= n; ++i){scanf("%d", &csh[i]);}scanf("%d%d", &S, &P);for(int i = 1; i <= n; ++i){if(dfn[i] == 0){tarjan(i);}}for(int i = 1; i <= n; ++i){for(int j = pnt[i]; j != nil; j = nxt[j]){if(isin[i] != isin[v[j]]){g[isin[i]].push_back(isin[v[j]]);}}}
}
void work()//spfa最长路,以前的DP写挫了。。。
{queue <int> Q;memset(vis, 0, sizeof(vis));memset(f, 0, sizeof(f));f[isin[S]] = hcash[isin[S]];Q.push(isin[S]);vis[isin[S]] = true;while(!Q.empty()){int t = Q.front();Q.pop();vis[t] = false;for(int i = 0; i < g[t].size(); ++i){if(f[g[t][i]] < f[t] + hcash[g[t][i]]){f[g[t][i]] = f[t] + hcash[g[t][i]];if(!vis[g[t][i]]){vis[g[t][i]] = true;Q.push(g[t][i]);}}}}int ans = 0, a;for(int i = 1; i <= P; ++i){scanf("%d", &a);ans = max(ans, f[isin[a]]);}printf("%d\n", ans);
}
int main()
{init();work();return 0;
}

非递归!APIO2009atm[抢掠计划]题解相关推荐

  1. 洛谷 P3627 [APIO2009]抢掠计划 题解

    Analysis 建图+强连通分量+SPFA求最长路 但要保证最后到达的点中包含酒馆 虽然思路并不难想,但要求的代码能力很高. 1 #include<iostream> 2 #includ ...

  2. bzoj 1179 抢掠计划atm (缩点+有向无环图DP)

    bzoj 1179 抢掠计划atm (缩点+有向无环图DP) 手动博客搬家: 本文发表于20170716 10:58:18, 原地址https://blog.csdn.net/suncongbo/ar ...

  3. 左神算法:分别用递归和非递归方式实现二叉树先序、中序和后序遍历(Java版)

    本题来自左神<程序员代码面试指南>"分别用递归和非递归方式实现二叉树先序.中序和后序遍历"题目. 题目 用递归和非递归方式,分别按照二叉树先序.中序和后序打印所有的节点 ...

  4. bzoj2054疯狂的馒头(巧用非递归并查集)

    www.cnblogs.com/shaokele/ bzoj2054:疯狂的馒头 Time Limit: 10 Sec Memory Limit: 162 MB Description Input 第 ...

  5. [L氏并查集] Python 列表法实现非递归并查集,轻松权重优化。

    一般的并查集都是用递归或者新建一个类来实现,这里介绍一种用Python来实现的非递归非函数并查集,这个方法暂时未在其他地方见过,尤其是中文领域目前还未见过,很可能是搜索引擎无法搜索到正确内容的原因,所 ...

  6. 【二叉树的遍历-3】后序遍历(递归与非递归)

    [二叉树的遍历-1]前序遍历(递归与非递归) [二叉树的遍历-2]中序遍历(递归与非递归) [二叉树的遍历-4]层序遍历(递归与非递归) 后序遍历 后序遍历(LRD)是二叉树遍历的一种,也叫做后根遍历 ...

  7. JavaSE_Java/C++模拟实现二叉树、C++/Java四种二叉树遍历题型(递归、非递归、Morris)遍历

    文章目录 1.Java模拟实现二叉树(前序构建二叉树) 2.C++模拟实现二叉树(层序构建二叉树) 3.Java/C++三种二叉树遍历方式 前序遍历 1)递归版本 2)非递归版本 3)Morris遍历 ...

  8. 常用十大算法 非递归二分查找、分治法、动态规划、贪心算法、回溯算法(骑士周游为例)、KMP、最小生成树算法:Prim、Kruskal、最短路径算法:Dijkstra、Floyd。

    十大算法 学完数据结构该学什么?当然是来巩固算法,下面介绍了十中比较常用的算法,希望能帮到大家. 包括:非递归二分查找.分治法.动态规划.贪心算法.回溯算法(骑士周游为例).KMP.最小生成树算法:P ...

  9. 【2023王道数据结构】【绪论】思维拓展-通过C++递归与非递归实现斐波那契数列C、C++完整实现(可直接运行)

    ~~~笔锋至此又怎能平淡而终,故事开始便不承认普通✌✌✌ ✌ 题目及题解持续更新中 [2023王道数据结构目录]课后算法设计题C.C++代码实现完整版大全 题目: 通过C++递归与非递归实现斐波那契数 ...

最新文章

  1. Java Web的Struts2的多语种网站的多语言切换实例
  2. 淡季不淡!速卖通户外运动产品好做吗?来看看法国这些爆款!
  3. 跳转语句_C/C++中的goto语句
  4. java中byte,String,InputStream之间的转换
  5. android launchmode java代码,java – Android:launchMode = SingleTask问题
  6. FreeRTOS学习笔记---动态创建任务 xTaskCreate() 源码分析
  7. jmeter报“msg“:“Content type ‘application/x-www-form-urlencoded;charset=UTF-8‘ not supported“的解决方法
  8. Atitit 管理体制 编号制 1.数字编码有何好处 数字编码有何好处 1、归档整理方便,特别在电子管理系统中; 2、数字编码更容易进行管理,无论谁进行的编码都是一样,管理方便,人员无论怎么换,程序
  9. python海龟画图(6)多边形(3)圆内接多边形
  10. 华中科技大学计算机启明班,华中科技大学启明学院创新实验班管理办法
  11. 微信公众号自动回复及多客服功能实现
  12. 数码照巧转胶片效果 美图秀秀制作质感写真
  13. 有三种钱,你花得越多,赚得越多!
  14. 自然数拆分(回溯法)
  15. 102条简短深刻的回答,看完人生豁然开朗
  16. 特斯拉是l3还是l2_特斯拉是l3还是l2
  17. How Does Linphone Toggle SIP Contact?
  18. Python 中的三元运算符,三目表达式
  19. XCTF-base64stego较为详细版
  20. 【收藏】机器学习数据库

热门文章

  1. 数据孤岛下的新破局 Real Time DaaS:面向 AP+TP 业务的数据平台架构
  2. 治数如治水,数据治理和数据创新难在哪?
  3. 对于nth-child()的理解
  4. 英文书法字体 免费字体下载_您可以免费下载45种美丽的字体
  5. 《UnityAPI.Network网络》(Yanlz+Unity+SteamVR+云技术+5G+AI+VR云游戏+Network+isClient+Connect+Server+立钻哥哥++OK++)
  6. RK3288 USB触摸屏与USB摄像头同时使用时触摸卡顿
  7. 当了10年程序员,我开窍了
  8. 设置博客园的背景图片,自定义样式以及导航目录
  9. 星驰云算GOSTAR,携手Swarm共建Web 3.0时代
  10. 中国网络伪黑客现象初探