板子传送门

根据题目意思,我们只需要找出一条点权最大的路径就行了,不限制点的个数。那么考虑对于一个环上的点被选择了,一整条环是不是应该都被选择,这一定很优,能选干嘛不选。很关键的是题目还允许我们重复经过某条边或者某个点,我们就不需要考虑其他了。因此整个环实际上可以看成一个点(选了其中一个点就应该选其他的点)

拓扑排序

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

照个人理解,拓扑排序通常是在DAG图中寻找一个适合的解决问题的顺序。

如何实现拓扑排序

方法1:BFS(SPFA优化)

1、先寻找入度为0的点,把它加入队列。

2、搜寻队列,把队列的点G删去,则如果有点的入度有G点的话,入度- -,当发现又出现入度为0的点时,将该点加入队列。

3、拓扑排序的结果为该队列,在执行删点操作的时候存储在一个数组及可。

方法2:记忆化搜索

大多数情况下,并不需要显式的拓扑排序

考虑朴素的回溯算法

若从一个给定的点出发,得到的结果是一样的

因此对于每个点,计算完成后可以把结果保存起来,之后直接返回查表的结果即可

拓扑排序伪代码(1):

Topological_sort(G){
统计图G中每个点的入度(可计算重边,但不可计算自环),记为degree[i]
初始化queue和result为空的队列,并将所有degree为0的点加入queue
while (!queue.empty()){
u = queue.pop() // 队首
result.push(u)
for e 是u的出边(若上面计算了重边,这里也要算,与上面一致)
v是e的指向的点
degree[v]--
if (degree[v] == ) queue.push(v)
}
return result
}

伪代码(2)

calculate(u){
if (u 已经搜索过) return table[u]
ans = -inf
for (v 是u的出边指向的点)
ans = max(ans, value[u] + calculate(v))
标记u已经搜索过
table[u] = ans
return ans
}
for (i 是G的所有节点)
result = max(result, calculate(i))
print(result)

为什么要dp

因为题目说了啊(逃),其实也很明显啦,对每个点都不断用他的入边的点更新他,取最大值,f[i]表示i点(缩点后)的经过点和最大值。

方程:

w代表当前点,rdr数组代表w点的入边的点,dis数组是权值。
f[w]=max(f[w],f[rdr[w][j-]]+dis_[w]);

完整AC代码:

#include<bits/stdc++.h>
using namespace std;
#define N 100010 inline int read(){
int x = ,s = ;
char c = getchar();
while(!isdigit(c)){
if(c == '-')s = -;
c = getchar();
}
while(isdigit(c)){
x = (x << ) + (x << ) + (c ^ '');
c = getchar();
}
return x * s;
} struct node{
int u, v;
int next;
} t[N];
int f[N];
int dfn[N], scc[N], low[N];
int stac[N], top = ;
bool vis[N];
int w[N], sum[N];//单点 + 缩点的值 int bian = ;
inline void add(int u, int v){
bian++;
t[bian].u = u;
t[bian].v = v;
t[bian].next = f[u];
f[u] = bian;
return ;
} int cnt = , cac = ;
void tarjan(int now){
dfn[now] = low[now] = ++cnt;
vis[now] = ;
stac[++top] = now;
for(int i = f[now]; i; i = t[i].next){
int u = t[i].u,v = t[i].v;
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[now] == low[now]){
int cur;
cac++;
do{
cur = stac[top--];
scc[cur] = cac;
vis[cur] = ;
sum[cac] += w[cur];
}while(cur != now);
}
return ;
} int dp[N];
void search(int now){
if(dp[now])return;
dp[now] = sum[now];
int maxn = ;
for(int i = f[now]; i;i = t[i].next){
int v = t[i].v;
if(!dp[v])search(v);
maxn = max(dp[v], maxn);
}
dp[now] += maxn;
return;
} int main(){
int n = read(), m = read();
for(int i = ;i <= n; i++)
w[i] = read();
for(int i = ;i <= m; i++){
int x = read(), y = read();
add(x, y);
}
for(int i = ;i <= n; i++)
if(!dfn[i]) tarjan(i);
bian = ;
memset(f, , sizeof(f));
for(int i = ;i <= m; i++){
t[i].next = ;
}
for(int i = ;i <= m; i++){
int u = t[i].u, v = t[i].v;
if(scc[u] != scc[v]){
add(scc[u], scc[v]);
}
}
int ans = -(~0u >> );
for(int i = ;i <= cac; i++){//注意是缩点的个数,这里是新图了
if(!dp[i]){
search(i);//进行记忆化搜索
ans = max(ans, dp[i]);
}
}
printf("%d\n", ans);
return ;
}

(板子)缩点 + DAG上的DP(深搜)luogu P3387的更多相关文章

  1. UVA 11324 The Largest Clique(缩点+DAG上的dp)

    求最大团.和等价性证明有类似之处,只不过这个不是求互推,而是只要a->b,或b->a即可. 同样的,容易想到先缩点,得到DAG,每个节点上保存SCC的点数,相信任意一条由根节点(入度为零) ...

  2. BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]

    方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...

  3. UVA - 10131Is Bigger Smarter?(DAG上的DP)

    题目:UVA - 10131Is Bigger Smarter? (DAG) 题目大意:给出一群大象的体重和IQ.要求挑选最多的大象,组成一个序列.严格的体重递增,IQ递减的序列.输出最多的大象数目和 ...

  4. P2668 斗地主 dp+深搜版

    题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4< ...

  5. bzoj1093: [ZJOI2007]最大半连通子图 scc缩点+dag上dp

    一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V ...

  6. BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998 题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置 ...

  7. NYOJ16 矩形嵌套 【DAG上的DP/LIS】

    矩形嵌套 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c ...

  8. DAG上的DP

    引例:NYOJ16 矩形嵌套 时间限制:3000 ms  |           内存限制:65535 KB 难度:4   描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可 ...

  9. 洛谷 P2392 kkksc03考前临时抱佛脚, dp / 深搜

    题目链接 P2392 kkksc03考前临时抱佛脚 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目 dp代码 #include <iostream> #includ ...

随机推荐

  1. 1-MyBatisPlus教程(一)

    1,简介 官网:http://mp.baomidou.com/ 参考教程:http://mp.baomidou.com/guide/ MyBatis-Plus(简称 MP)是一个 MyBatis 的增 ...

  2. 【Hadoop离线基础总结】CDH版本Hadoop 伪分布式环境搭建

    CDH版本Hadoop 伪分布式环境搭建 服务规划 步骤 第一步:上传压缩包并解压 cd /export/softwares/ tar -zxvf hadoop-2.6.0-cdh5.14.0.tar ...

  3. hive数据仓库入门到实战及面试

    第一章.hive入门 一.hive入门手册 1.什么是数据仓库 1.1数据仓库概念 对历史数据变化的统计,从而支撑企业的决策.比如:某个商品最近一个月的销量,预判下个月应该销售多少,从而补充多少货源. ...

  4. js使用经验--if...else简化

    目的 在项目中,if else语句如果用得很多,特别是嵌套,代码不美观,阅读性不好.所以的话,用其他的方式简化替换if...else...就很有必要. 简化的作用就是赠人玫瑰,手留余香.对自己对项目对 ...

  5. 黑马程序员_毕向东_Java基础视频教程——位运算符(随笔)

    位运算符 左移和右移 左移 左移越移越大. 往左移几位就相当于这个数乘于2的几次方 3 << 2 --> 3 * 2^2 = 3 * 4 = 12 3 << 3 --&g ...

  6. 前后端分离产生的跨域问题的解决方案之--jsonp、nginx代理、设置头信息等

    前言 在前后端没有分离的时候,前端开发要么是写静态页面,数据渲染后端来做,要么就是前端的页面和后端的代码刚开始的时候就合并在一起,每次后端代码更新了之后,前端也要更新一下代码,然后重启一下服务,还是比 ...

  7. 百度智能云平台调用食物识别api Java实现

    纪录一下我小学期2天花了20小时写的菜品识别java程序. 1.2. 百度智能云简介 1.2.1 百度图像识别服务 百度图像识别服务,基于深度学习及大规模图像训练,准确识别图片中的物体类别.位置.置信 ...

  8. HTML5 Canvas绘图如何使用

    --------------复制而来--原地址http://jingyan.baidu.com/article/ed15cb1b2e642a1be369813e.html HTML5 Canvas绘图 ...

  9. sql语句 怎么从一张表中查询数据插入到另一张表中?

    sql语句 怎么从一张表中查询数据插入到另一张表中?  ----原文地址:http://www.phpfans.net/ask/MTc0MTQ4Mw.html 比如我有两张表 table1 字段 un ...

  10. System.Web.mail ----虚拟发件人发送邮件

     转载别人的 使用SMTP发送邮件   说到邮件发送,先提一下SMTP. SMTP的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议.它是一组用于从源地址到目的 ...