刷题向》图论》BZOJ1179 关于tarjan和SPFA的15秒(normal)
这道题可以考察图论的掌握程度(算半道水题)
题目如下
输入
第一行包含两个整数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
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的单向的道路到达其中的至少一个酒吧。
题解
这道题考到了spfa和tarjan唯一需要考虑的地方是,当你tarjan一遍之后,你需要做缩点,那么缩点之后你要做的事是重建整张图,把同一强连通分量里的点缩到同一点,再次建边,然后就是裸SPFA的事情了(缩点的过程用并查集考虑)
下面贴出代码
1 #include<cstdio> 2 #include<cstring> 3 struct shit{ 4 int aim; 5 int next; 6 int get; 7 bool use; 8 }e[520000]; 9 int max(int x,int y) 10 { 11 return x>y?x:y; 12 } 13 int min(int x,int y) 14 { 15 return x<y?x:y; 16 } 17 int point,head[520000],n,m,ass,cnt,stack[520000],low[520000],time[520000],a,b,T; 18 int father[520000],quq[520000],val[520000],d[520000],star,ans; 19 bool f[520000]; 20 void fuck(int x,int y) 21 { 22 e[++point].aim=y; 23 e[point].get=x; 24 e[point].next=head[x]; 25 head[x]=point; 26 } 27 void rebuild() 28 { 29 memset(head,0,sizeof(head)); 30 point=0; 31 for(int i=1;i<=m;i++) 32 if(father[e[i].get]==father[e[i].aim]); 33 else fuck(father[e[i].get],father[e[i].aim]); 34 } 35 void tarjan(int sb) 36 { 37 low[sb]=time[sb]=++T; 38 f[sb]=true; 39 stack[++ass]=sb; 40 for(int k=head[sb];k!=0;k=e[k].next) 41 { 42 if(!time[e[k].aim]) 43 { 44 tarjan(e[k].aim); 45 low[sb]=min(low[sb],low[e[k].aim]); 46 } 47 else if(f[e[k].aim])low[sb]=min(low[sb],time[e[k].aim]); 48 } 49 if(time[sb]==low[sb]) 50 { 51 f[sb]=false; 52 while(stack[ass]!=sb) 53 { 54 val[sb]+=val[stack[ass]]; 55 f[stack[ass]]=false; 56 father[stack[ass--]]=sb; 57 } 58 ass--; 59 } 60 } 61 void SPFA(int num) 62 { 63 memset(f,0,sizeof(f)); 64 star=0,ass=1; 65 quq[++star]=num,f[num]=true,d[num]=val[num]; 66 while(star<=ass) 67 { 68 int u=quq[star++]; 69 for(int k=head[u];k!=0;k=e[k].next) 70 { 71 int v=e[k].aim; 72 if(d[u]+val[v]>d[v]) 73 { 74 d[v]=d[u]+val[v]; 75 if(f[v])continue; 76 quq[++ass]=v; 77 f[v]=true; 78 } 79 } 80 f[u]=false; 81 } 82 return ; 83 } 84 int main() 85 { 86 scanf("%d%d",&n,&m); 87 for(int i=1;i<=m;i++) 88 { 89 scanf("%d%d",&a,&b); 90 fuck(a,b); 91 } 92 for(int i=1;i<=n;i++) 93 { 94 father[i]=i; 95 scanf("%d",&val[i]); 96 } 97 for(int i=1;i<=n;i++)if(!time[i])tarjan(i); 98 rebuild(); 99 scanf("%d%d",&a,&b); 100 SPFA(father[a]); 101 for(int i=1;i<=b;i++) 102 { 103 scanf("%d",&a); 104 ans=max(ans,d[father[a]]); 105 } 106 printf("%d",ans); 107 return 0; 108 }