非递归!APIO2009atm[抢掠计划]题解
题目描述
输入描述 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[抢掠计划]题解相关推荐
- 洛谷 P3627 [APIO2009]抢掠计划 题解
Analysis 建图+强连通分量+SPFA求最长路 但要保证最后到达的点中包含酒馆 虽然思路并不难想,但要求的代码能力很高. 1 #include<iostream> 2 #includ ...
- bzoj 1179 抢掠计划atm (缩点+有向无环图DP)
bzoj 1179 抢掠计划atm (缩点+有向无环图DP) 手动博客搬家: 本文发表于20170716 10:58:18, 原地址https://blog.csdn.net/suncongbo/ar ...
- 左神算法:分别用递归和非递归方式实现二叉树先序、中序和后序遍历(Java版)
本题来自左神<程序员代码面试指南>"分别用递归和非递归方式实现二叉树先序.中序和后序遍历"题目. 题目 用递归和非递归方式,分别按照二叉树先序.中序和后序打印所有的节点 ...
- bzoj2054疯狂的馒头(巧用非递归并查集)
www.cnblogs.com/shaokele/ bzoj2054:疯狂的馒头 Time Limit: 10 Sec Memory Limit: 162 MB Description Input 第 ...
- [L氏并查集] Python 列表法实现非递归并查集,轻松权重优化。
一般的并查集都是用递归或者新建一个类来实现,这里介绍一种用Python来实现的非递归非函数并查集,这个方法暂时未在其他地方见过,尤其是中文领域目前还未见过,很可能是搜索引擎无法搜索到正确内容的原因,所 ...
- 【二叉树的遍历-3】后序遍历(递归与非递归)
[二叉树的遍历-1]前序遍历(递归与非递归) [二叉树的遍历-2]中序遍历(递归与非递归) [二叉树的遍历-4]层序遍历(递归与非递归) 后序遍历 后序遍历(LRD)是二叉树遍历的一种,也叫做后根遍历 ...
- JavaSE_Java/C++模拟实现二叉树、C++/Java四种二叉树遍历题型(递归、非递归、Morris)遍历
文章目录 1.Java模拟实现二叉树(前序构建二叉树) 2.C++模拟实现二叉树(层序构建二叉树) 3.Java/C++三种二叉树遍历方式 前序遍历 1)递归版本 2)非递归版本 3)Morris遍历 ...
- 常用十大算法 非递归二分查找、分治法、动态规划、贪心算法、回溯算法(骑士周游为例)、KMP、最小生成树算法:Prim、Kruskal、最短路径算法:Dijkstra、Floyd。
十大算法 学完数据结构该学什么?当然是来巩固算法,下面介绍了十中比较常用的算法,希望能帮到大家. 包括:非递归二分查找.分治法.动态规划.贪心算法.回溯算法(骑士周游为例).KMP.最小生成树算法:P ...
- 【2023王道数据结构】【绪论】思维拓展-通过C++递归与非递归实现斐波那契数列C、C++完整实现(可直接运行)
~~~笔锋至此又怎能平淡而终,故事开始便不承认普通✌✌✌ ✌ 题目及题解持续更新中 [2023王道数据结构目录]课后算法设计题C.C++代码实现完整版大全 题目: 通过C++递归与非递归实现斐波那契数 ...
最新文章
- Java Web的Struts2的多语种网站的多语言切换实例
- 淡季不淡!速卖通户外运动产品好做吗?来看看法国这些爆款!
- 跳转语句_C/C++中的goto语句
- java中byte,String,InputStream之间的转换
- android launchmode java代码,java – Android:launchMode = SingleTask问题
- FreeRTOS学习笔记---动态创建任务 xTaskCreate() 源码分析
- jmeter报“msg“:“Content type ‘application/x-www-form-urlencoded;charset=UTF-8‘ not supported“的解决方法
- Atitit 管理体制 编号制 1.数字编码有何好处 数字编码有何好处 1、归档整理方便,特别在电子管理系统中; 2、数字编码更容易进行管理,无论谁进行的编码都是一样,管理方便,人员无论怎么换,程序
- python海龟画图(6)多边形(3)圆内接多边形
- 华中科技大学计算机启明班,华中科技大学启明学院创新实验班管理办法
- 微信公众号自动回复及多客服功能实现
- 数码照巧转胶片效果 美图秀秀制作质感写真
- 有三种钱,你花得越多,赚得越多!
- 自然数拆分(回溯法)
- 102条简短深刻的回答,看完人生豁然开朗
- 特斯拉是l3还是l2_特斯拉是l3还是l2
- How Does Linphone Toggle SIP Contact?
- Python 中的三元运算符,三目表达式
- XCTF-base64stego较为详细版
- 【收藏】机器学习数据库
热门文章
- 数据孤岛下的新破局 Real Time DaaS:面向 AP+TP 业务的数据平台架构
- 治数如治水,数据治理和数据创新难在哪?
- 对于nth-child()的理解
- 英文书法字体 免费字体下载_您可以免费下载45种美丽的字体
- 《UnityAPI.Network网络》(Yanlz+Unity+SteamVR+云技术+5G+AI+VR云游戏+Network+isClient+Connect+Server+立钻哥哥++OK++)
- RK3288 USB触摸屏与USB摄像头同时使用时触摸卡顿
- 当了10年程序员,我开窍了
- 设置博客园的背景图片,自定义样式以及导航目录
- 星驰云算GOSTAR,携手Swarm共建Web 3.0时代
- 中国网络伪黑客现象初探