题目描述:
Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。
Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆祝他的胜利。
使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机 里面就不会再有钱了。 例如,假设该城中有 6 个路口,道路的连接情况如下图所示:
市中心在路口 1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表
示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢 劫的现金总数为 47,实施的抢劫路线是:1-2-4-1-2-3-5。
输入:
第一行包含两个整数 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
输出样例:
47
思路分析:
这一题的思路十分简单,就是通过Tarjan算法根据强连通分量进行缩点,
然后将所缩的点的所存的金额与是否有酒吧的状态做出来,
然后用得出来的新图进行一个SPFA算法的操作得出最大值。
最后的答案是从有酒吧的缩点求最大值。
代码实现:
#include<cstdio>
#include<iostream>
#include<queue>
#include<stack>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int n,m,dfn[500005],low[500005],p1,bel[500005],p2,ans[500005],st,ans1;
struct node{
int h,z;
}a[500005];
struct nooe{
int h1,z1;
}di[500005];
vector<int>G[500005];
vector<int>G1[500005];
bool v1[500005];
stack<int>q;
queue<int>s;
void Tarjan(int x)
{
p1++;
low[x]=p1;
dfn[x]=p1;
q.push(x);
v1[x]=1;
for(int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(!dfn[v])
{
Tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(v1[v])
low[x]=min(low[x],dfn[v]);
}
if(low[x]==dfn[x])
{
int p;
p2++;
do{
p=q.top();
q.pop();
v1[p]=0;
bel[p]=p2;
}while(p!=x);
}
}
void SPFA()
{
ans[st]=di[st].h1;
s.push(st);
memset(v1,0,sizeof(v1));
v1[st]=1;
while(!s.empty())
{
int t=s.front();
v1[t]=0;
s.pop();
for(int i=0;i<G1[t].size();i++)
{
int v=G1[t][i];
if(ans[v]<ans[t]+di[v].h1)
{
ans[v]=ans[t]+di[v].h1;
if(!v1[v])
{
v1[v]=1;
s.push(v);
}
}
}
}
}
int read()
{
int x=0,f=1;
char s=getchar();
while(s<'0'||s>'9')
{
if(s=='-')
f=-1;
s=getchar();
}
while(s>='0'&&s<='9')
{
x*=10;
x+=s-'0';
s=getchar();
}
return x*f;
}
int main()
{
n=read();
m=read();
int a1,b;
for(int i=1;i<=m;i++)
{
a1=read();
b=read();
G[a1].push_back(b);
}
for(int i=1;i<=n;i++)
a[i].h=read();
int q,s;
s=read();
q=read();
for(int i=1;i<=q;i++)
{
a1=read();
a[a1].z=1;
}
v1[s]=1;
for(int i=1;i<=n;i++)
if(!dfn[i])
Tarjan(i);
for(int i=1;i<=n;i++)
{
di[bel[i]].h1+=a[i].h;
if(a[i].z==1)
di[bel[i]].z1=1;
if(i==s)
st=bel[i];
for(int j=0;j<G[i].size();j++)
if(bel[i]!=bel[G[i][j]])
G1[bel[i]].push_back(bel[G[i][j]]);
}
SPFA();
for(int i=1;i<=p2;i++)
if(di[i].z1==1)
ans1=max(ans1,ans[i]);
printf("%d",ans1);
}