非递归!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] >

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值