题目描述
输入
第一行包含两个整数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
题解:
我们发现题目中描述的每一个ATM只能抢一个,而且是有向图,所以考虑Tarjan来进行缩点,再跑一遍SPFA就好了
注意S和酒吧的编号要按缩点之后的图来;
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
const int MAXN=500003;
namespace tarjan
{
int dfn[MAXN],low[MAXN],sta[MAXN],color[MAXN],num[MAXN];
int top,ctot,Time;
}
int n,m,S,P,x[MAXN],y[MAXN],p[MAXN],val[MAXN],head[MAXN],dis[MAXN],vis[MAXN],cnt;
struct Edge
{
int next,to;
}edge[MAXN];
using namespace tarjan;
using namespace std;
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void Add_Edge(int u,int v)
{
edge[++cnt]=(Edge){head[u],v};
head[u]=cnt;
}
void Clear()
{
memset(edge,0,sizeof(edge));
memset(head,0,sizeof(head));
cnt=0;
memset(dis,0,sizeof(dis));
}
void SPFA(int s)
{
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> que;
que.push(s);
vis[s]=1;
dis[s]=num[s];
while(!que.empty())
{
int c=que.front();
que.pop();
vis[c]=0;
for(int i=head[c];i;i=edge[i].next)
{
int v=edge[i].to;
if(dis[v]<dis[c]+num[v])
{
dis[v]=dis[c]+num[v];
if(vis[v]==0)
{
que.push(v);
vis[v]=1;
}
}
}
}
return ;
}
void Tarjan(int x)
{
dfn[x]=low[x]=++Time;
vis[x]=1,sta[++top]=x;
for(int i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
Tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(vis[v]) low[x]=min(low[x],low[v]);
}
if(low[x]==dfn[x])
{
ctot++;
do
{
color[sta[top]]=ctot;
num[ctot]+=val[sta[top]];
vis[sta[top]]=0;
}while(sta[top--]!=x);
}
return ;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
{
int X,Y;
X=read(),Y=read();
Add_Edge(X,Y);
x[i]=X;
y[i]=Y;
}
for(int i=1;i<=n;i++) val[i]=read();
S=read(),P=read();
for(int i=1;i<=n;i++)
if(!dfn[i]) Tarjan(i);
Clear();
for(int i=1;i<=m;i++)
{
if(color[x[i]]!=color[y[i]]) Add_Edge(color[x[i]],color[y[i]]);
}
SPFA(color[S]);
for(int i=1;i<=P;i++)
scanf("%d",&p[i]);
int ans=0;
for(int i=1;i<=P;i++)
{
ans=max(ans,dis[color[p[i]]]);
}
printf("%d",ans);
return 0;
}