BZOJ 1179 Atm 题解
BZOJ 1179 Atm 题解
SPFA Algorithm
Tarjan Algorithm
Description

Input
第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号
Output
输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。
Sample Input
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
HINT
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
————————————————————————————分割线————————————————————————————
思路:
先用Tarjan算法求出途中的所有强连通分量,再讲每个分量值加和为点,再用SPFA算法求出以S为源点,最大价值的路径。
代码如下,(不是我的代码)
//Code By にしきのまき #include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
struct node
{
int v;
int next;
};
int n,m;
node e[],map[];//邻接表存图
int st[],head[],cnt;
int atm[],money[];
int d[],q[];//最短路径&SPFA要用的队列
void build(int a,int b)
{
e[++cnt].v=b;
e[cnt].next=st[a];
st[a]=cnt;
}//建图找强连通分量
int stack[],top;//tarjan需要的栈
int dfn[],low[],dex;//时间戳(深搜序)、可回溯到的最早栈中时间戳、次序编号
bool vis[];//tarjan时判断点是否在栈中,SPFA时判断点是否在队列中
int color[],num;//表示同一强连通分量上的点
void tarjan(int x)//tarjan找强连通分量
{
dfn[x]=++dex;
low[x]=dex;
vis[x]=true;
stack[++top]=x;//当前点入栈
int i;
for(i=st[x];i!=;i=e[i].next)//枚举以当前点为起点的边
{
int temp=e[i].v;//temp为当前被枚举边的终点
if(!dfn[temp])//如果当前边终点未被处理
{
tarjan(temp);
low[x]=min(low[x],low[temp]);
}
else if(vis[temp])low[x]=min(low[x],dfn[temp]);
}
if(dfn[x]==low[x])
{
vis[x]=false;
color[x]=++num;//标记当前强连通分量内的点
while(stack[top]!=x)//栈顶元素依次出栈
{
color[stack[top]]=num;
vis[stack[top--]]=false;
}
top--;
}
}
void add()// 把同一强连通分量上的点缩成一个点,把这些点连成一张新图
{
cnt=;
int i,j;
for(i=;i<=n;i++)
{
for(j=st[i];j!=;j=e[j].next)
{
int temp=e[j].v;
if(color[i]!=color[temp])
{
map[++cnt].v=color[temp];
map[cnt].next=head[color[i]];
head[color[i]]=cnt;
}
} }
}
void spfa(int x)//SPFA找最长路
{
memset(vis,false,sizeof(vis));
int l=,r=;
q[l]=x;//初始点放入队列
vis[x]=true;
d[x]=money[x];
while(l<=r)
{
int u=q[l++];
for(int i=head[u];i!=;i=map[i].next)//遍历所有以当前点为起点的边
{
int v=map[i].v;
if(d[v]<d[u]+money[v])
{
d[v]=d[u]+money[v];
if(vis[v])continue;
q[++r]=v;//如果当前拓展的边的终点不在队列里,就把它放入队尾
vis[v]=true;
}
}
vis[u]=false;
}
}
int main()
{
int a,b,i,s,p,o,ans=;
scanf("%d%d",&n,&m);
for(i=;i<=m;i++)
{
scanf("%d%d",&a,&b);
build(a,b);
}//建初始图
for(i=;i<=n;i++)
{
if(!dfn[i])tarjan(i);//找强连通分量
}
add();//建新图
for(i=;i<=n;i++)
{
scanf("%d",&atm[i]);
money[color[i]]+=atm[i];
}
scanf("%d%d",&s,&p);
spfa(color[s]);//找单源最短路
for(i=;i<=p;i++)
{
scanf("%d",&o);
ans=max(ans,d[color[o]]);//找到以酒吧为终点的最长路
}
printf("%d",ans);
return ;
}
2016-09-14 20:00:54
(完)
BZOJ 1179 Atm 题解的更多相关文章
- bzoj 1179 Atm
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1179 题解: 一道比较综合的图论题 直接讲正解: 如果这个图G中存在某个强连通分量,那么这 ...
- BZOJ 1179 Atm(强连通分量缩点+DP)
题目说可以通过一条边多次,且点权是非负的,所以如果走到图中的一个强连通分量,那么一定可以拿完这个强连通分量上的money. 所以缩点已经很明显了.缩完点之后图就是一个DAG,对于DAG可以用DP来求出 ...
- bzoj 1179 [APIO 2009]Atm(APIO水题) - Tarjan - spfa
Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一 ...
- BZOJ 1179 [Apio2009]Atm(强连通分量)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1179 [题目大意] 给出一张有向带环点权图,给出一些终点,在路径中同一个点的点权只能累 ...
- BZOJ 1179: [Apio2009]Atm( tarjan + 最短路 )
对于一个强连通分量, 一定是整个走或者不走, 所以tarjan缩点然后跑dijkstra. ------------------------------------------------------ ...
- bzoj 1179 [Apio2009]Atm 缩点+最短路
[Apio2009]Atm Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 4290 Solved: 1893[Submit][Status][Dis ...
- BZOJ 1179 抢掠计划atm (缩点+有向无环图DP)
手动博客搬家: 本文发表于20170716 10:58:18, 原地址https://blog.csdn.net/suncongbo/article/details/81061601 https:// ...
- bzoj 1179[Apio2009]Atm (tarjan+spfa)
题目 输入 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一 ...
- bzoj 1179: [Apio2009]Atm
Description Input 第 一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路 的起点和终点的 ...
随机推荐
- repo 版本回退
转自:http://blog.csdn.net/wed110/article/details/52179386 1.repo 回退到具体某一天的提交 repo forall -c 'ID=`Git l ...
- Android消息推送怎么实现?
在开发Android和iPhone应用程序时,我们往往需要从服务器不定的向手机客户端即时推送各种通知消息,iPhone上已经有了比较简单的和完美的推送通知解决方案,可是Android平台上实现起来却相 ...
- Bootstrap简介
接下来的一段时间,想研究一下现有的网页框架,第一个不容错过的就是Bootstrap,Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架.Bootstrap 是基于 HTML.CS ...
- 为什么是 n(n+1)/2 ?
n(n+1)/2是一个数列的元素两两运算后的不重复结果数.如图: 假如数列a = 1,2,3....n.那么该数列内的元素两两相乘,则会构建出上图中的表格,这个表格应该有n x n 个元素. 用程序写 ...
- 在windows系统的文件右键菜单中增加“命令提示符”
本实用小工具能够在windows系统的文件右键菜单中增加“命令提示符”,方便快速进入制定文件的命令提示窗口,避免逐层输入或复制文件夹路径,极其实用. 工具下载地址如下:360云盘(访问密码:5b71) ...
- POJ 1984 Navigation Nightmare 带全并查集
Navigation Nightmare Description Farmer John's pastoral neighborhood has N farms (2 <= N <= ...
- LISP学习-开发环境以及hello world
我想说说关于common lisp的开发环境问题,学习一个新的语言,如何最简单的搭建一个开发环境是至关重要的,它应该不让你在其他方面花费太多的精力,而只专注于学习语言本身. 其实我刚开始尝试的并不是c ...
- python学习第三天
小结: 总体上,python是解释型语言,开源比较好,速度较慢,装逼神器,解释器较常用的是CPython,安装后python进入运行环境 exit()退出 第一个hello world : print ...
- 用户层获取TEB PEB结构地址 遍历进程模块.doc
1.fs寄存器指向TEB结构 2.在TEB+0x30地方指向PEB结构 3.在PEB+0x0C地方指向PEB_LDR_DATA结构 4.在PEB_LDR_DATA+0x1C地方就是一些动态连接库地址了 ...
- codeforces724-B. Batch Sort
想着想着就忘了有什么问题没解决,坑啊 一开始读错题意了,而且一着急写了两大段差不多的代码,冗余度啊,不说了.. 显然的一点,给的数据是绝对离散的,每行都是1~m的排列 难点一.如何移动能使未排序的数组 ...