Tarjan+topsort(DP)【P3387】 [模板]缩点

Description

给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

Input

第一行,n,m

第二行,n个整数,依次代表点权

第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

Output

共一行,最大的点权之和。

缩点+DP这是题目说的

先缩点,对于每一个联通块之间建边,这时得到一张(DAG)(有向无环图)

我们对其跑拓扑排序,然后开一个数组(dis)记录到达某个点的最大值.

对于那些入度为0的点,我们初始化其(dis)为其联通块的点权之和.

然后每次取(max)即可.

最终(ans)即为对到达每个点的(dis)(max)

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define R register

using namespace std;

const int gz=50008;

inline void in(int &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}

int head[gz],tot,val[gz],v[gz],h[gz],dis[gz],ins[gz],ans,n,m;

struct cod{int u,v;}edge[gz<<1],e[gz<<1];

inline void add(R int x,R int y)
{
	edge[++tot].u=head[x];
	edge[tot].v=y;
	head[x]=tot;
}

inline void ado(R int x,R int y)
{
	e[++tot].u=h[x];
	e[tot].v=y;
	h[x]=tot;
}

int dfn[gz],belong[gz],idx,low[gz],stk[gz],top,col;

bool inq[gz];

void tarjan(R int x)
{
	low[x]=dfn[x]=++idx;
	stk[++top]=x;inq[x]=true;
	for(R int i=head[x];i;i=edge[i].u)
	{
		if(!dfn[edge[i].v])
		{
			tarjan(edge[i].v);
			low[x]=min(low[x],low[edge[i].v]);
		}
		else if(inq[edge[i].v])
			low[x]=min(low[x],dfn[edge[i].v]);
	}
	if(low[x]==dfn[x])
	{
		int now=-1;
		col++;
		while(now!=x)
		{
			now=stk[top--];
			belong[now]=col;
			inq[now]=false;
			v[col]+=val[now];
		}
	}
}

inline void topsort()
{
	top=0;
	for(R int i=1;i<=col;i++)
		if(!ins[i])stk[++top]=i,dis[i]=v[i];
	while(top)
	{
		int u=stk[top--];
		for(R int i=h[u];i;i=e[i].u)
		{
			ins[e[i].v]--;
			dis[e[i].v]=max(dis[e[i].v],dis[u]+v[e[i].v]);
			if(!ins[e[i].v])stk[++top]=e[i].v;
		}
	}
	for(R int i=1;i<=col;i++)
		ans=max(ans,dis[i]);
	printf("%d
",ans);
}

int main()
{
	in(n),in(m);
	for(R int i=1;i<=n;i++)in(val[i]);
	for(R int i=1,x,y;i<=m;i++)
	{
		in(x),in(y);
		add(x,y);
	}
	for(R int i=1;i<=n;i++)
		if(!dfn[i])tarjan(i);
	tot=0;
	for(R int i=1;i<=n;i++)
		for(R int j=head[i];j;j=edge[j].u)
			if(belong[i]!=belong[edge[j].v])
			{
				ins[belong[edge[j].v]]++;
				ado(belong[i],belong[edge[j].v]);
			}
	topsort();
}
原文地址:https://www.cnblogs.com/-guz/p/9899509.html