BZOJ1179 [Apio2009]Atm
Description
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的单向的道路到达其中的至少一个酒吧。
正解:tarjan+SPFA
解题报告:
首先如果有环那么走进一个环上的点,显然把整个环都跑一遍会更优,也就是说一个强连通分量是完全一体的,所以可以直接缩环成点,然后跑最长路即可。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long LL; 15 #define RG register 16 const int MAXN = 500011; 17 const int MOD = 500000; 18 int n,m,ecnt,belong[MAXN],cnt,ans; 19 int first[MAXN],next[MAXN],to[MAXN]; 20 int quan[MAXN],s,p,dfn[MAXN],low[MAXN]; 21 bool bar[MAXN],pd[MAXN],in[MAXN]; 22 int stack[MAXN],top; 23 int head[MAXN],dis[MAXN],a[MAXN],l,tail,dui[MAXN]; 24 struct edge{ 25 int to,next; 26 }e[MAXN]; 27 struct node{ 28 int dis,x; 29 bool operator < (const node &a)const{ 30 return a.dis>dis; 31 } 32 }tmp; 33 priority_queue<node>Q; 34 35 inline int getint() 36 { 37 RG int w=0,q=0; RG char c=getchar(); 38 while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 39 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; 40 } 41 42 inline void tarjan(RG int x){ 43 pd[x]=1; dfn[x]=low[x]=++ecnt; stack[++top]=x; 44 for(RG int i=first[x];i;i=next[i]) { 45 RG int v=to[i]; 46 if(!dfn[v]) tarjan(v),low[x]=min(low[v],low[x]); 47 else if(pd[v]) low[x]=min(low[x],low[v]); 48 } 49 if(dfn[x]==low[x]) { 50 cnt++; 51 for(;;top--) { 52 belong[stack[top]]=cnt; 53 pd[stack[top]]=0; 54 if(stack[top]==x) { top--; break; } 55 } 56 } 57 } 58 59 inline void SPFA(){ 60 dis[s]=a[s]; 61 dui[++tail]=s; 62 while(l!=tail) { 63 l++; l%=MOD; RG int u=dui[l]; in[u]=0; 64 for(int i=head[u];i;i=e[i].next) { 65 RG int v=e[i].to; 66 if(dis[v]<dis[u]+a[v]) { 67 dis[v]=dis[u]+a[v]; 68 if(!in[v]) { 69 in[v]=1; dui[++tail]=v; 70 tail%=MOD; 71 } 72 } 73 } 74 } 75 for(RG int i=1;i<=cnt;i++) if(pd[i]) ans=max(ans,dis[i]); 76 printf("%d",ans); 77 } 78 79 inline void work(){ 80 n=getint(); m=getint(); int x,y; 81 for(RG int i=1;i<=m;i++) { 82 x=getint(); y=getint(); 83 next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; 84 } 85 for(RG int i=1;i<=n;i++) quan[i]=getint(); 86 s=getint(); p=getint(); for(RG int i=1;i<=p;i++) x=getint(),bar[x]=1; 87 ecnt=0; for(RG int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 88 for(int i=1;i<=n;i++) if(!belong[i]) belong[i]=++cnt; 89 ecnt=0; memset(pd,0,sizeof(pd));//判断环内是否有酒吧 90 s=belong[s]; 91 for(RG int i=1;i<=n;i++) { 92 if(bar[i]) pd[belong[i]]=1; 93 a[belong[i]]+=quan[i]; 94 for(RG int j=first[i];j;j=next[j]) { 95 if(belong[i]==belong[to[j]]) continue; 96 x=belong[i]; y=belong[to[j]]; 97 e[++ecnt].next=head[x]; head[x]=ecnt; e[ecnt].to=y; 98 } 99 } 100 SPFA(); 101 } 102 103 int main() 104 { 105 work(); 106 return 0; 107 }
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!