[BZOJ1179][APIO2009][强连通分量Tarjan+spfa]ATM
Posted Reddest
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1179][APIO2009][强连通分量Tarjan+spfa]ATM相关的知识,希望对你有一定的参考价值。
[BZOJ1179][APIO2009]ATM
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
Sample Output
47
HINT
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
题目大意:在一个各个点都有权值有向图中,从一个点出发,走过的点权值清零。要求问如何走所得的总权值最大,并且可以在酒吧点结束。
题目分析:如果若干个点处在同一个强连通分量中,那么从这个强连通分量中任意一个节点出发必定能到达这个强连通分量中的任意一个点。所以可以把这些点用Tarjan缩成一个点,把强连通分量中的所有的点权加到那个缩成的点,然后把这些缩成的点重构图跑一遍spfa,输出到所有酒吧点的路中最长的即可。
下面贴AC代码:
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 int n,m,cnt,re_cnt,S,P,CN,maxn,top,dfs_num; 5 int pre[1000010],re_pre[1000010],bar[1000010],DFN[1000010],LOW[1000010],dye[1000010],size[1000010],tow[1000010],vis[1000010],w[1000010],dist[1000010]; 6 struct pack{int to,next,d;} E[1000010],re_E[1000010]; 7 void add_edge(int x,int y){ 8 E[++cnt].to=y; 9 E[cnt].next=pre[x]; 10 pre[x]=cnt; 11 } 12 void rebuild(){ 13 for(int i=1;i<=n;++i) 14 for(int j=pre[i];j;j=E[j].next) 15 if(dye[i]!=dye[E[j].to]&&dye[i]&&dye[E[j].to]){ 16 re_E[++re_cnt].to=dye[E[j].to]; 17 re_E[re_cnt].next=re_pre[dye[i]]; 18 re_E[re_cnt].d=size[dye[E[j].to]]; 19 re_pre[dye[i]]=re_cnt; 20 } 21 } 22 void tarjan(int pos){ 23 vis[tow[++top]=pos]=1; 24 DFN[pos]=LOW[pos]=++dfs_num; 25 for(int i=pre[pos];i;i=E[i].next){ 26 if(!DFN[E[i].to]){ 27 tarjan(E[i].to); 28 LOW[pos]=min(LOW[pos],LOW[E[i].to]); 29 } 30 else if(vis[E[i].to]) 31 LOW[pos]=min(LOW[pos],DFN[E[i].to]); 32 } 33 if(DFN[pos]==LOW[pos]){ 34 vis[pos]=0; 35 size[dye[pos]=++CN]+=w[pos]; 36 while(pos!=tow[top]){ 37 size[dye[tow[top]]=CN]+=w[tow[top]]; 38 vis[tow[top--]]=0; 39 } 40 --top; 41 } 42 } 43 int spfa(int pos){ 44 vis[pos]=1; 45 for(int i=re_pre[pos];i;i=re_E[i].next){ 46 int v=re_E[i].to; int k=re_E[i].d; 47 if(dist[pos]+k>dist[v]){ 48 dist[v]=dist[pos]+k; 49 if(!vis[v]){ 50 if(spfa(re_E[i].to)) return 1; 51 } 52 else return 1; 53 } 54 } 55 vis[pos]=0; 56 return 0; 57 } 58 int main(){ 59 scanf("%d%d",&n,&m); 60 if(!n||!m) {printf("0");return 0;} 61 for(int i=1;i<=m;++i){ 62 int a,b; 63 scanf("%d%d",&a,&b); 64 add_edge(a,b); 65 } 66 for(int i=1;i<=n;++i) 67 scanf("%d",&w[i]); 68 scanf("%d%d",&S,&P); 69 for(int i=1;i<=P;++i){ 70 int t; 71 scanf("%d",&t); 72 bar[t]=1; 73 } 74 for(int i=1;i<=n;++i) 75 if(!dye[i]) 76 tarjan(i); 77 rebuild(); 78 dist[dye[S]]=size[dye[S]]; 79 spfa(dye[S]); 80 for(int i=1;i<=n;++i) 81 if(bar[i]) 82 if(dist[dye[i]]>maxn) 83 maxn=dist[dye[i]]; 84 printf("%d",maxn); 85 return 0; 86 }
以上是关于[BZOJ1179][APIO2009][强连通分量Tarjan+spfa]ATM的主要内容,如果未能解决你的问题,请参考以下文章