【Tarjan】+【SPFA】APIO2009 Atm
一、算法介绍
tarjan——求解有向图强连通分量。这个算法在本人的一篇blog中有介绍,这里就不赘述了。贴上介绍tarjan的的blog链接:http://www.cnblogs.com/Maki-Nishikino/p/5866191.html
那么接下来说说SPFA:
SPFA全称Shortest Path Faster Algorithm,用于求解单源最短路。既然名字中有“Faster”,那它就一定有过人之处,事实上它也的确比Dijkstra和Bellman-Ford更高效。
它的思路大致如下:
1、先用邻接表把图存下来,并且规定一个数组d,d[i]表示起点到i的最短路程;
2、建立一个队列,将起点放入队列;
3、对队首元素执行松弛操作,遍历所有以队首元素为起点的边,如果被遍历的边可以使到被遍历的边的终点的路径变短,那么就更新这个最短路径,并把被遍历的边的终点放到队尾;
4、每完成一次松弛,就令队首元素出队,重复3,直到队列里没有元素。
原谅博主懒得贴伪代码,我就直接讲题了,反正题解里也有模板#手动滑稽
二、APIO2009 Atm题解
原题链接(来自bzoj):http://www.lydsy.com/JudgeOnline/problem.php?id=1179
题目描述:
输入:
第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口
编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来
的一行中有P个整数,表示P个有酒吧的路口的编号。
输出:
输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。
样例输入:
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
样例输出:
47
数据范围:
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
对于这道题,我们考虑先用tarjan求出它的所有强连通分量,再把同一个强连通分量上的ATM机的钱加起来,让一个强连通分量上的点缩成一个点。然后以市中心s为起点,用SPFA跑出s到其他点的最长(最有价值)路,比较酒吧所在点的d值,输出大的即可。
附上代码:
- #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 ;
- }
APIO2009 Atm
弱弱地说一句,本蒟蒻码字也不容易,转载请注明出处http://www.cnblogs.com/Maki-Nishikino/p/5868953.html
【Tarjan】+【SPFA】APIO2009 Atm的更多相关文章
- 【HDOJ4635】【Tarjan缩点+思维】【经典】
http://acm.hdu.edu.cn/showproblem.php?pid=4635 Strongly connected Time Limit: 2000/1000 MS (Java/Oth ...
- 【次短路径/SPFA】BZOJ1726-[Usaco2006 Nov]Roadblocks第二短路
[题目大意] 求无向图点1到n的次短路. [思路] 一年多前写过一次堆优化Dijkstra的,方法就是一边跑Dijsktra一边就把次短路径保存下来.和一般Dijkstra不同的是把vis数组去掉了, ...
- 【tarjan求割顶】BZOJ2730-[HNOI2012]矿场搭建
[题目大意] 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍 ...
- poj 3592 Instantaneous Transference 【SCC +缩点 + SPFA】
Instantaneous Transference Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 6204 Accep ...
- 【HDOJ2586】【Tarjan离线求LCA】
http://acm.hdu.edu.cn/showproblem.php?pid=2586 How far away ? Time Limit: 2000/1000 MS (Java/Others) ...
- LOJ2421 NOIP2015 信息传递 【tarjan求最小环】
LOJ2421 NOIP2015 信息传递 LINK 题目大意就是给你一个有向图,求最小环 有一个很奇妙的性质叫做每个点只有一条出边 然后我们考虑对每个强联通分量进行考虑 发现每个强联通分量内的边数一 ...
- 【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图
思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于 ...
- bzoj 1023: [SHOI2008]cactus仙人掌图【tarjan+dp+单调队列】
本来想先求出点双再一个一个处理结果写了很长发现太麻烦 设f[u]为u点向下的最长链 就是再tarjan的过程中,先照常处理,用最长儿子链和次长儿子链更新按ans,然后处理以这个点为根的环,也就是这个点 ...
- bzoj 1556: 墓地秘密【状压dp+spfa】
显然是状压,显然不可能把所有格子压起来 仔细观察发现只有机关周围的四个格子有用以及起点,所以我们用spfa处理出这些格子两两之间的距离(注意细节--这里写挂了好几次),然后设f[s][i]为碰完的机关 ...
- bzoj 1093: [ZJOI2007]最大半连通子图【tarjan+拓扑排序+dp】
先tarjan缩成DAG,然后答案就变成了最长链,dp的同时计数即可 就是题面太唬人了,没反应过来 #include<iostream> #include<cstdio> #i ...
随机推荐
- Python 基础 - 统计文本里单词的个数以及出现的次数
# -*- coding:utf-8 -*- #author:V def tol (file1,gui): #写一个方法,定义文件,or 匹配规则 import re patt = re.compil ...
- 读取文件内容fopen,fgets,fclose
<?php //首先采用“fopen”函数打开文件,得到返回值的就是资源类型.$file_handle = fopen("/data/webroot/resource/php/f.tx ...
- 通过Queue的构造函数的可选参数maxsize来设定队列长度
创建一个"队列"对象 import Queuemyqueue = Queue.Queue(maxsize = 10) Queue.Queue类即是一个队列的同步实现.队列长度可为无 ...
- Leetcode | Linked List Cycle I && II
一.判断链表是否存在环,办法为: 设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针 ...
- ServletContext读取Web应用中的资源文件
package cn.itcast; import java.io.FileInputStream; import java.io.IOException; import java.io.InputS ...
- GDC2016 Epic Games【Bullet Train】 新风格的VR-FPS的制作方法
追求“舒适”和“快感”的VR游戏设计方法 http://game.watch.impress.co.jp/docs/news/20160318_749016.html [Bullet Tr ...
- 杂-lowbit
int lowbit(int x){ )); } int lowbit(int x){ return x&-x; }
- 序列化(Serialization)据为JSONP远端请求
Insus.NET前些日子,有分享了一段代码,<使用JSONP跨域请求数据>http://www.cnblogs.com/insus/p/3512271.html 是使用jQuery的Da ...
- 《linux内核设计与实现》读书笔记第十八章
第18章 调试 18.1 准备开始 准备工作需要的是: 一个bug 一个藏匿bug的内核版本 相关内核代码的知识和运气 18.2 内核中的bug 内核中bug的产生原因 从明白无误的错误代码——没有把 ...
- 安装sphinx
安装Sphinx全文检索服务器 Sphinx默认不支持中文索引及检索, 以前用Coreseek的补丁来解决,目前Coreseek 不单独提供补丁文件,而基于sphinx开发了Coreseek 全文检索 ...