#图# #SPFA# #Tarjan# ----- BZOJ1179
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#图# #SPFA# #Tarjan# ----- BZOJ1179相关的知识,希望对你有一定的参考价值。
SPFA算法
- SPFA(Shortest Path Faster Algorithm)(队列优化)算法是求单源最短路径的一种算法。
- 判负环(在差分约束系统中会得以体现)。如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)
tarjan算法
Tarjan算法是用来求有向图的强连通分量的。
Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。
当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
BZOJ 1179
Input
第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号
Output
输出一个整数,表示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
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
HINT
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 6 int n,m,st,p; 7 int ans; 8 int money[500010],moneys[500010]; 9 int q[500010],b,e,d[500010];//spfa 10 int stack[500010],dfn[500010],low[500010],index,top;//tarjan 11 bool vis[500010]; 12 int color[500010],num; 13 14 struct node{ 15 int u; 16 int v; 17 int next; 18 }s[500010],map[500010]; 19 int head[500010],rehead[500010],cnt; 20 21 void add(int x,int y){ 22 s[++cnt].u=x; 23 s[cnt].v=y; 24 s[cnt].next=head[x]; 25 head[x]=cnt; 26 } 27 28 void tarjan(int x){ 29 dfn[x]=++index; 30 low[x]=index; 31 stack[++top]=x; 32 vis[x]=true; 33 34 for(int i=head[x];i!=0;i=s[i].next){ 35 if(!dfn[s[i].v]){ 36 tarjan(s[i].v); 37 low[x]=min(low[x],low[s[i].v]); 38 } 39 else if(vis[s[i].v]==true)low[x]=min(low[x],dfn[s[i].v]); 40 } 41 42 if(dfn[x]==low[x]){ 43 vis[x]=false; 44 color[x]=++num;//计算个数 45 while(stack[top]!=x){ 46 color[stack[top]]=num; 47 vis[stack[top--]]=false; 48 } 49 top--; 50 } 51 } 52 53 void rebuild(){//缩点 54 cnt=0; 55 for(int i=1;i<=n;i++){ 56 for(int j=head[i];j!=0;j=s[j].next){ 57 if(color[i]!=color[s[j].v]){ 58 map[++cnt].u=color[i]; 59 map[cnt].v=color[s[j].v]; 60 map[cnt].next=rehead[color[i]]; 61 rehead[color[i]]=cnt; 62 } 63 } 64 } 65 } 66 67 void spfa(int x){ 68 memset(vis,false,sizeof(vis)); 69 q[++b]=x; 70 e++; 71 vis[x]=true; 72 d[x]=moneys[x]; 73 while(b<=e){ 74 int y=q[b++]; 75 for(int i=rehead[y];i!=0;i=map[i].next){ 76 if(d[map[i].v]<d[y]+moneys[map[i].v]){ 77 d[map[i].v]=d[y]+moneys[map[i].v]; 78 if(!vis[map[i].v]){ 79 q[++e]=map[i].v; 80 vis[map[i].v]=true; 81 } 82 } 83 } 84 vis[q[b]]=false; 85 } 86 } 87 88 int main(){ 89 90 scanf("%d%d",&n,&m); 91 for(int i=1;i<=m;i++){ 92 int a,b; 93 scanf("%d%d",&a,&b); 94 add(a,b); 95 } 96 97 for(int i=1;i<=n;i++) 98 if(!dfn[i])tarjan(i); 99 100 rebuild();//重建图 101 102 for(int i=1;i<=n;i++){ 103 scanf("%d",&money[i]); 104 moneys[color[i]]+=money[i]; 105 } 106 107 scanf("%d%d",&st,&p); 108 109 spfa(color[st]); 110 111 for(int i=1;i<=p;i++){ 112 int a; 113 scanf("%d",&a); 114 ans=max(ans,d[color[a]]); 115 } 116 printf("%d",ans); 117 118 return 0; 119 }
以上是关于#图# #SPFA# #Tarjan# ----- BZOJ1179的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ1179] [Apio2009]Atm(tarjan缩点 + spfa)
BZOJ_1179_[Apio2009]Atm_tarjan+spfa
[BZOJ 1179]ATM题解 Tarjan缩点+SPFA