Luogu P3387 【模板】缩点
https://www.luogu.org/problemnew/show/P3387
题目背景
缩点+DP
题目描述
给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
输入输出格式
输入格式:
第一行,n,m
第二行,n个整数,依次代表点权
第三至m+2行,每行两个整数u,v,表示u->v有一条有向边
输出格式:
共一行,最大的点权之和。
输入输出样例
输入样例#1: 复制
2 2 1 1 1 2 2 1
输出样例#1: 复制
2
说明
n<=10^4,m<=10^5,点权<=1000
算法:Tarjan缩点+DAGdp
#include<cstdio>
#include<iostream>
using namespace std;
int read()
{
int ret=0;
char ch=getchar();
while(ch<"0"||ch>"9") ch=getchar();
while(ch>="0"&&ch<="9")
ret=(ret<<1)+(ret<<3)+ch-"0",
ch=getchar();
return ret;
}
const int N=1e6+5;
int n,m,a[N],b[N],ans,f[N];
struct NA{
int u,v;
}e[N];
int cnt,he[N],to[N],nxt[N];
int sgn,dfn[N],low[N],st[N],top,col,co[N];
inline void add(int u,int v)
{
to[++cnt]=v;
nxt[cnt]=he[u];
he[u]=cnt;
}
void tarjan(int u)
{
low[u]=dfn[u]=++sgn;
st[++top]=u;
for(int e=he[u];e;e=nxt[e])
{
int v=to[e];
if(!dfn[v])
tarjan(v),low[u]=min(low[u],low[v]);
else if(!co[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
co[u]=++col;
while(top&&st[top]!=u)
co[st[top--]]=col;
top--;
}
}
void dfs(int u)
{
for(int e=he[u];e;e=nxt[e])
{
int v=to[e];
if(!f[v]) dfs(v);
f[u]=max(f[u],f[v]);
}
f[u]+=b[u];
ans=max(ans,f[u]);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=m;i++)
e[i].u=read(),e[i].v=read(),
add(e[i].u,e[i].v);
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
b[co[i]]+=a[i];
cnt=0;
for(int i=1;i<=col;i++) he[i]=0;
for(int i=1;i<=m;i++)
if(co[e[i].u]!=co[e[i].v])
add(co[e[i].v],co[e[i].u]);
for(int i=1;i<=col;i++)
if(!f[i]) dfs(i);
printf("%d
",ans);
return 0;
}
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇:Android 更换桌面图标不生效问题解决
- 下一篇:多年iOS开发经验总结(转)