[APIO2009]抢掠计划(tarjan+spfa)
来源:互联网 发布:mysql高效编程 编辑:程序博客网 时间:2024/05/23 17:55
题目描述
Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。
Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。
使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个路口,道路的连接情况如下图所示:
市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表
示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。
输入输出格式
输入格式:
第一行包含两个整数 N、M。N 表示路口的个数,M 表示道路条数。接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表示第 i 条道路的起点和终点的路口编号。接下来 N 行,每行一个整数,按顺序表示每 个路口处的 ATM 机中的钱数。接下来一行包含两个整数 S、P,S 表示市中心的 编号,也就是出发的路口。P 表示酒吧数目。接下来的一行中有 P 个整数,表示 P 个有酒吧的路口的编号。
输出格式:
输出一个整数,表示 Banditji 从市中心开始到某个酒吧结束所能抢劫的最多 的现金总数。
输入输出样例:
输入样例#1:
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
输出样例#1:
47
思路:考虑有环存在自然要先tarjan缩点,然后spfa跑最长路就可以了。
题解:
#include<iostream>#include<cstdio>#include<stack>#include<cstring>#include<queue>using namespace std;const int maxn=500000+10;struct cc{ int from,to;}es[maxn],es2[maxn];int first[maxn],nxt[maxn];int first2[maxn],nxt2[maxn];int tot=0;void build(int ff,int tt){ es[++tot]=(cc){ff,tt}; nxt[tot]=first[ff]; first[ff]=tot;}int num[maxn];bool f[maxn];stack<int>s;int cnt=0,scc_cnt=0;int scc_num[maxn];int low[maxn],dfn[maxn];int dfs(int u){ s.push(u); low[u]=dfn[u]=++cnt; for(int i=first[u];i;i=nxt[i]) { int v=es[i].to; if(!dfn[v]) { low[v]=dfs(v); low[u]=min(low[u],low[v]); } else if(!scc_num[v]) { low[u]=min(low[u],low[v]); } } if(low[u]==dfn[u]) { scc_cnt++; while(!s.empty()) { int v=s.top(); s.pop(); scc_num[v]=scc_cnt; if(u==v) { break; } } } return low[u];}void build2(int ff,int tt){ es2[++tot]=(cc){ff,tt}; nxt2[tot]=first2[ff]; first2[ff]=tot;}int sum[maxn];bool vis[maxn];int dis[maxn];queue<int>q;int ans=0;void spfa(int s){ q.push(s); vis[s]=1; dis[s]+=sum[s]; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=first2[u];i;i=nxt2[i]) { int v=es2[i].to; if(dis[v]<dis[u]+sum[v]) { dis[v]=dis[u]+sum[v]; if(f[v]) { ans=max(ans,dis[v]); } if(!vis[v]) { q.push(v); vis[v]=1; } } } }}int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); build(x,y); } for(int i=1;i<=n;i++) { scanf("%d",&num[i]); } int s,p; scanf("%d%d",&s,&p); dfs(s); for(int i=1;i<=p;i++) { int x; scanf("%d",&x); f[scc_num[x]]=1; } tot=0; for(int i=1;i<=n;i++) { if(!vis[i]) { vis[i]=1; sum[scc_num[i]]+=num[i]; } for(int j=first[i];j;j=nxt[j]) { int v=es[j].to; if(scc_num[i]!=scc_num[v]) { build2(scc_num[i],scc_num[v]); } else { if(!vis[v]) { vis[v]=1; sum[scc_num[v]]+=num[v]; } } } } memset(vis,0,sizeof(vis)); spfa(scc_num[s]); printf("%d",ans); return 0;}
- [APIO2009]抢掠计划(tarjan+spfa)
- APIO2009 抢掠计划
- APIO2009 抢掠计划
- [APIO2009]抢掠计划
- P3627 [APIO2009]抢掠计划
- 省选专练APIO2009抢掠计划
- 【Bzoj1179】[Apio2009]抢掠计划atm
- Tarjan+最长路——BZOJ1179/Luogu3627 [APIO2009]ATM 抢掠计划
- 【bzoj1179】[Apio2009]抢掠计划atm 强连通分量缩点+spfa
- bzoj 1179: [Apio2009]Atm (spfa+tarjan)
- [BZOJ1179][Apio2009]Atm(tarjan+spfa)
- 【bzoj 1179】[Apio2009]Atm(Tarjan+spfa)
- 【BZOJ1179】【APIO2009】Atm(tarjan+spfa)
- 【APIO2009】【强连通分量】【DAG】抢掠计划
- 【APIO2009】BZOJ1179 BSOJ2468 CODEVS1611 抢掠计划
- [bzoj1179][Apio2009]Atm Tarjan+spfa
- bzoj1179: [Apio2009]Atm tarjan+spfa
- APIO抢掠计划(浅谈Tarjan——(4))
- BZOJ4518:征途(dp+斜率优化)
- Gojs 去掉水印
- Java代码编写规范
- python中 if __name__ =='__main__'的作用
- 负k进制
- [APIO2009]抢掠计划(tarjan+spfa)
- 【LintCode-632】二叉树的最大节点(Java实现)
- linux shell基础知识
- 猜糖果
- java-day15api的概述: 就是java替我们写好的一些类,他封装了一些功能,我们仅仅只需要知道如何使用即可
- [BZOJ]3679: 数字之积 数位DP
- 51nod 1769 Clarke and math2 线性筛+数学
- C
- 线程