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条道路 的起点和终点的 ...
随机推荐
- Delphi的Win32的API调用简单介绍
1. 介绍Win32 API和Win32系统.还要讨论Win32系统的功能以及它与16位系统在功能上的几个主要区别.只是让对Win32系统有一个基本的了解.当已经基本了解Win32操作后,就可 ...
- Sexagenary Cycle(天干地支法表示农历年份)
Sexagenary Cycle Time Limit: 2 Seconds Memory Limit: 65536 KB 题目链接:zoj 4669 The Chinese sexagen ...
- .NET Expression Tree
Expression Tree 第一个简单的例子. [TestMethod] public void GodTest() { Expression<Func<int, int, int&g ...
- [Unity3d插件]EasyTouch的初步使用
对于移动平台上的RPG类的游戏,我们常用虚拟摇杆来控制人物角色的行走和一些行为,相信我们对它并不陌生,之前尝试了EasyTouch2.5,发现并没有最新版的3.1好用,2.5版本的对于自适应没有做的很 ...
- android:layout_weight属性详解 (转)
在android开发中LinearLayout很常用,LinearLayout的内控件的android:layout_weight在某些场景显得非常重要,比如我们需要按比例显示.android并没用提 ...
- PHP isset()与empty()的使用区别详解(转)
通过对PHP语言的学习,应该知道它是基于函数的一款HTML脚本语言.庞大的函数库支持着PHP语言功能的实现.下面我们为大家介绍有关PHP函数isset()与empty()的相关用法. PHP的 ...
- 64位ubuntu下重新编译hadoop2.2流水账
hadoop官方网站中只提供了32位的hadoop-2.2.0.tar.gz,如果要在64位ubuntu下部署hadoop-2.2.0,就需要重新编译源码包,生成64位的部署包.建议以下操作使用roo ...
- tnsnames.ora 监听配置文件详解
今天是重要的一天.将XML数据导入ORACLE遇到很多问题,学了好多,其中很长时间花在网络配置上,刚开始学,具体原因不知道,先把搜集到的好文章存下来,以后慢慢研究. 监听配置文件 ...
- AJAX案例二:简单表单验证
案例:如果用户名输入为张三,那么在失去焦点时后面会显示该用户名已被注册,否则显示可以注册! <%@ page language="java" import="jav ...
- 用PHP链接mysql数据库
PHP提供了两套数据库可用于访问mysql数据库 1)MySQL扩展函数数据库 2)MySQLI扩展数据库(improved) 使用MySQLI函数访问MySQL数据库步骤 1)链接数据库管理系统 m ...