您的位置:首页 > 运维架构

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

2018-11-03 06:53 399 查看

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\n",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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: