[bzoj]1179 ATM
1179: [Apio2009]Atm
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 4645 Solved: 2054
[Submit][Status][Discuss]
Description
Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruser
i 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。Bandit
ji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他
途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利。使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的
现金数额。他希 望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可 以经过同一路口
或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个
路口,道路的连接情况如下图所示:
市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表示。每个 ATM 机中可取的钱数标在了
路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。
Input
第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。
接下来M行,每行两个整数,这两个整数都在1到N之间,
第i+1行的两个整数表示第i条道路的起点和终点的路口编号。
接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。
接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。
接下来的一行中有P个整数,表示P个有酒吧的路口的编号
N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。
输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
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
Tarjan缩点之后,跑一遍spfa求最长路就行了。
中间因为变量,初始化问题死了好多次,我会在代码里写出我给自己挖的坑。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<vector> 8 #include<stack> 9 #include<map> 10 using namespace std; 11 #define mem(a,b) memset(a,b,sizeof(a)) 12 #define ll long long 13 #define inf 1000000000 14 #define maxn 500000+100 15 #define maxm 500000+100 16 struct node 17 { 18 int to,next; 19 } edge[maxm]; 20 int n,m,head[maxn],vis[maxn],dfn[maxn],low[maxn],cdu[maxn],num[maxn],cnt,timi,stack1[maxn],top,cut,rdu[maxn]; 21 int mon[maxn],jiu[maxn],ss,p,from[maxn],go[maxn],s1[maxn],d[maxn],q[maxn],c[maxn]; 22 stack <int> s; 23 inline int read() 24 { 25 int x=0,f=1;char ch=getchar(); 26 while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} 27 while(ch>='0'&&ch<='9') {x=10*x+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 void init() 31 { 32 memset(dfn,0,sizeof(dfn)); 33 memset(low,0,sizeof(low)); 34 memset(head,-1,sizeof(head)); 35 memset(vis,0,sizeof(vis)); 36 memset(num,0,sizeof(num)); 37 memset(cdu,0,sizeof(cdu)); 38 memset(rdu,0,sizeof(rdu)); 39 mem(jiu,0); 40 mem(c,0); 41 //while(!s.empty()) s.pop(); 42 cnt=0; 43 timi=1; 44 top=0; 45 cut=0; 46 } 47 void addedge(int u,int v) 48 { 49 edge[cnt].to=v; 50 edge[cnt].next=head[u]; 51 head[u]=cnt; 52 cnt++; 53 } 54 void tarjan(int u) 55 { 56 dfn[u]=timi; 57 low[u]=timi; 58 timi++; 59 s.push(u); 60 vis[u]=1; 61 for(int i=head[u]; i!=-1; i=edge[i].next) 62 { 63 int v=edge[i].to; 64 if(!dfn[v]) 65 { 66 tarjan(v); 67 low[u]=min(low[u],low[v]); 68 } 69 else 70 { 71 if(vis[v]) 72 low[u]=min(low[u],dfn[v]); 73 } 74 } 75 if(low[u]==dfn[u]) 76 { 77 cut++; 78 int x=s.top(); 79 while(x!=u) 80 { 81 vis[x]=0; 82 num[x]=cut; 83 s1[cut]+=mon[x]; 84 //printf("cut=%d s1=%d \n",cut,s1[cut]); 85 if(jiu[x]) c[cut]=1; 86 s.pop(); 87 x=s.top(); 88 } 89 num[x]=cut; 90 s1[cut]+=mon[x];//我今天又在这里死了,你不能因为人家在外面你就不管人家啊。。瞎浪 91 if(jiu[x]) c[cut]=1; 92 //printf("cut=%d s1=%d \n",cut,s1[cut]); 93 vis[x]=0; 94 s.pop(); 95 } 96 } 97 void spfa() 98 { 99 for(int i=1;i<=cut;++i) d[i]=0; 100 mem(vis,0); 101 int l=0,r=1,x,y; 102 103 q[1]=num[ss];d[num[ss]]=s1[num[ss]]; 104 //cout<<q[1]<<endl; 105 //cout<<l<<" "<<r<<endl; 106 while(l!=r) 107 { 108 x=q[++l]; 109 //cout<<head[x]<<endl; 110 if(l==maxn) l=0;vis[x]=0; 111 for(int i=head[x];i!=-1;i=edge[i].next) 112 { 113 // cout<<"i="<<i<<endl; 114 if(d[x]+s1[y=edge[i].to]>d[y]) 115 { 116 d[y]=d[x]+s1[y]; 117 // cout<<"y="<<y<<endl; 118 if(!vis[y]) 119 { 120 vis[y]=1;q[++r]=y;if(r==maxn) r=0; 121 } 122 } 123 } 124 } 125 } 126 int main() 127 { 128 init();//第一次跑不出来死在这里,没有初始化,今天在这个地方死第二次了(微笑 129 int x,y; 130 n=read();m=read(); 131 for(int i=1;i<=m;++i) 132 { 133 int a,b; 134 a=read();b=read(); 135 from[i]=a;go[i]=b; 136 addedge(a,b); 137 } 138 for(int i=1;i<=n;++i) mon[i]=read(); 139 ss=read();p=read(); 140 for(int i=1;i<=p;++i) 141 { 142 int h=read();jiu[h]=1; 143 } 144 for(int i=1;i<=n;++i) 145 if(!dfn[i]) tarjan(i); 146 mem(head,-1); 147 cnt=0; 148 for(int i=1;i<=m;++i) 149 { 150 if(num[x=from[i]]!=num[y=go[i]]) addedge(num[x],num[y]);//最后发现死在了这里,我真的是zz,缩点后不用缩点。。 151 } 152 spfa(); 153 int ans=0; 154 //for(int i=1;i<=n;++i) cout<<num[i]<<" "<<mon[i]<<endl; 155 //cout<<cut<<endl; 156 //for(int i=1;i<=cut;++i) cout<<s1[i]<<endl; 157 for(int i=1;i<=cut;++i) if(c[i]) ans=max(ans,d[i]); 158 cout<<ans<<endl; 159 }