本文同步发表于https://www.zybuluo.com/Gary-Ying/note/1235385

题目描述

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

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

输入输出格式

输入格式:

第一行,n,m

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

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

输出格式:

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

样例输入

2 2
1 1
1 2
2 1

样例输出

2

数据范围

\(n<=10^4\),\(m<=10^5\),\(点权<=1000\)

题解

算法

正如题目名称所说,这道题需要使用缩点的技巧,那么这是为什么呢?

我们可以把一个强连通分量近似看作一个环,由于这道题中边权只能取1次,每个点和每条边可以经过多次,所以一个强连通分量中的点一定可以全部取到。并且强连通分量中各点的出边可以看做是同一点的出边。于是我们可以高兴地说:

这道题中一个强连通分量相当于一个点,我们可以缩点了!

缩点以后图就变成了DAG(有向无环图),对于有向无环图,注定是要与拓扑排序为伴的。DP转移方程如下:(dp[v]表示走到v点的最大路径长度,a[v]表示v这个强连通分量中所有点的点权之和)

\[dp[v]=max\{dp[u]+a[v]\}
\]

转移的条件是存在边(u,v)。用拓扑排序转移DP即可(避免后效性,保证处理v的转移时u的转移已经处理)。

易错点(其实就是我错的)

1、第37行:if (vis[v])low[u] = min(low[u], dfn[v]);

2、

for (int i = 1; i <= n; ++i)
if (!dfn[i])tarjan(i);

3、 第84行:addedge1(color[i],color[v]);

Code

#include<iostream>
#include<cstdio>
using namespace std; const int maxn = 10007;
const int maxm = 100007;
int n, m;
int c[maxn], a[maxn];
int edgenum, head[maxn], Next[maxm], vet[maxm];
int edgenum1, head1[maxn], Next1[maxm], vet1[maxm];
int dfn[maxn], low[maxn], stamp;
int stack[maxn], top, color[maxn], num;
int init[maxn];
bool vis[maxn]; void addedge(int u, int v){
++edgenum;
vet[edgenum] = v;
Next[edgenum] = head[u];
head[u] = edgenum;
}
void addedge1(int u, int v){
++edgenum1;
vet1[edgenum1] = v;
Next1[edgenum1] = head1[u];
head1[u] = edgenum1;
++init[v];
}
void tarjan(int u){
dfn[u] = low[u] = ++stamp;
stack[++top] = u; vis[u] = true;
for (int e = head[u]; e; e = Next[e]){
int v = vet[e];
if (!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}else if (vis[v])low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]){
color[u] = ++num; vis[u] = false;
while (stack[top] != u) vis[stack[top]] = false, color[stack[top--]] = num;
--top;
}
} void tp(){
int head = 0, tail = -1, que[maxn], dp[maxn];
for (int i = 1; i <= num; ++i) {
if (init[i] == 0){
que[++tail] = i;
}
dp[i] = a[i];
}
while (head <= tail){
int u = que[head]; ++head;
for (int e = head1[u]; e; e = Next1[e]){
int v = vet1[e];
--init[v];
if (init[v] == 0) que[++tail] = v;
dp[v] = max(dp[v], dp[u] + a[v]);
}
}
int ans = 0;
for (int i = 1; i <= num; ++i)
if (dp[i] > ans) ans = dp[i];
printf("%d\n", ans);
} int main(){
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d", &c[i]);
for (int i = 1; i <= m; ++i){
int u, v;
scanf("%d%d", &u, &v);
addedge(u,v);
}
for (int i = 1; i <= n; ++i)
if (!dfn[i])tarjan(i);
for (int i = 1; i <= n; ++i){
for (int e = head[i]; e; e = Next[e]){
int v = vet[e];
if (color[i]!=color[v]){
addedge1(color[i],color[v]);
}
}
a[color[i]] += c[i];
}
tp();
return 0;
}

【Luogu3381】【模板】缩点的更多相关文章

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

    Description 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次 ...

  2. Tarjan的缩点&&割点概述

    What is Tarjan? Tarjan,是一种用来解决图的联通性的一种有效途径,它的一般俗称叫做:缩点.我们首先来设想一下: 如果我们有一个图,其中A,B,C构成一个环,那么我们在某种条件下,如 ...

  3. Cogs 1298.通讯问题

    1298.通讯问题 ★ 输入文件:jdltt.in 输出文件:jdltt.out 简单对比 时间限制:1 s 内存限制:128 MB [题目描述] 一个篮球队有n个篮球队员,每个队员都有联系方式(如电 ...

  4. Ural 1382 2SAT

    ural1382 直接套用 2SAT模板 缩点 拓扑排序... #include<iostream> #include<cstdio> #include<cstdlib& ...

  5. 图论算法-Tarjan模板 【缩点;割顶;双连通分量】

    图论算法-Tarjan模板 [缩点:割顶:双连通分量] 为小伙伴们总结的Tarjan三大算法 Tarjan缩点(求强连通分量) int n; int low[100010],dfn[100010]; ...

  6. Tarjan总结(缩点+割点(边)+双联通+LCA+相关模板)

    Tarjan求强连通分量 先来一波定义 强连通:有向图中A点可以到达B点,B点可以到达A点,则称为强连通 强连通分量:有向图的一个子图中,任意两个点可以相互到达,则称当前子图为图的强连通分量 强连通图 ...

  7. tarjan 缩点(模板)

    描述: 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 注:允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次. 思路: ...

  8. 洛谷P3387 【模板】缩点 题解

    背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...

  9. 洛谷——P3387 【模板】缩点

    P3387 [模板]缩点 题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点, ...

随机推荐

  1. 利用SVD-推荐未尝过的菜肴2

    推荐未尝过的菜肴-基于SVD的评分估计 实际上数据集要比我们上一篇展示的myMat要稀疏的多. from numpy import linalg as la from numpy import * d ...

  2. azkaban使用

    新建一个text文件,a.job,打包成zip包传到azkaban即可 方式1:job流   1. a.job内容范例: type=command command=hive shell command ...

  3. python requests 正则爬虫

    代码: import requests from multiprocessing import Pool from requests.exceptions import RequestExceptio ...

  4. 交换机的vlan文章

    https://blog.csdn.net/standmyground/article/details/3933364 大家知道,交换机会把广播报文(目的mac地址全1的报文)和未知单播报文从所有端口 ...

  5. golang ffmpeg 做网络直播

    最近在公司做在线视频转码的工作,研究了下ffmpeg 最后直接研究了下网络直播,我是在我自己的mac 上面测试的,效果,还可以,先看看效果图吧 ffmpeg 我是通过brew安装 的,这步就略了 VL ...

  6. The connection string 'MysqlEF' in the application's configuration file does not contain the require异常

    在学习EF core first 对接mysql时,出现了这个异常. 原因是:连接字符串中缺少providerName="MySql.Data.MySqlClient" <a ...

  7. python之 MySQLdb 实践 爬一爬号码

    0.目录 2.构建URL3.新建数据库4.新建汇总表5.定义连接数据库函数:connect_db(db=None, cursorclass=DictCursor)6.汇总表填充必要数据7.新建各省份子 ...

  8. Understanding about numerical stability, convergence and consistency

    In a computer simulation of the real world, physical quantities, which usually have continuous distr ...

  9. NEST - Elasticsearch 的高级客户端

    NEST - High level client Version:5.x 英文原文地址:NEST - High level client 个人建议:学习 NEST 的官方文档时,按照顺序进行,不宜跳来 ...

  10. python全栈开发day51-jquery插件、@media媒体查询、移动端单位、Bootstrap框架

    一.昨日内容回顾 技术行业 (1)ajax技术 XMLHttpRequest() <1>创建XMLHttpRequest()对象 <2>检测状态(通过readyState的改变 ...