【tarjan】P3627 [APIO2009]抢掠计划

由于路和银行都可以重复走,而银行里的钱只能被抢走一次,所以考虑到tarjan缩点,之后跑spfa的最长路即可

代码

#include<bits/stdc++.h>
using namespace std;
int n,m,s,p,top,times;
const int maxn=5e5+5;
const int inf=0x3f3f3f3f;
int S,T,dis[maxn],st[maxn],vis[maxn],h[maxn],tot,x[maxn],y[maxn],col_type,col[maxn],sum[maxn],in[maxn],money[maxn],head[maxn],dfn[maxn],low[maxn],cnt;
struct edge
{
	int to,nxt;
}G[maxn];
struct edgee
{
	int to,nxt,v;
}e[maxn];
void Add(int x,int y, int z)
{
	e[++tot].to=y; e[tot].nxt=h[x]; e[tot].v=z; h[x]=tot;
}
int spfa()
{
	for(int i=0;i<=n;i++) dis[i]=-inf; 
	dis[S]=0; vis[S]=1; 
	queue <int> q; q.push(S);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=h[u];i;i=e[i].nxt)
		{
			int to=e[i].to;
			int v=e[i].v;
			if(dis[to]<dis[u]+v)
			{
				dis[to]=dis[u]+v;
				if(!vis[to])
				{
					vis[to]=1;
					q.push(to);
				}
			}
		}
		 vis[u]=0;
	}
	return dis[T];
}
void add(int x ,int y)
{
	G[++cnt].to=y; G[cnt].nxt=head[x]; head[x]=cnt;
}
void tarjan(int x)
{
	low[x]=dfn[x]=++times;
	st[++top]=x; in[x]=1;
	for(int i=head[x];i;i=G[i].nxt)
	{
		int to=G[i].to;
		if(!dfn[to])
		{
			tarjan(to);
			low[x]=min(low[x],low[to]);
		}
		else if(in[to]) low[x]=min(low[x],dfn[to]);
	}
	if(low[x]==dfn[x])
	{
		col_type++;
		while(st[top+1]!=x)
		{
			sum[col_type]+=money[st[top]];
			in[st[top]]=0;
			col[st[top--]]=col_type;
		}
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]),add(x[i],y[i]);
	for(int i=1;i<=n;i++) scanf("%d",&money[i]);
	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
	S=0; T=col_type+1; int bar;
	scanf("%d%d",&s,&p);
	for(int i=1;i<=m;i++) if(col[x[i]]!=col[y[i]]) Add(col[x[i]],col[y[i]],sum[col[y[i]]]);
	Add(S,col[s],sum[col[s]]);
	for(int i=1;i<=p;i++) scanf("%d",&bar),Add(col[bar],T,0);
	printf("%d\n",spfa());
	return 0;
}

猜你喜欢

转载自blog.csdn.net/andyc_03/article/details/107594493