(板子)缩点 + DAG上的DP(深搜)luogu P3387
根据题目意思,我们只需要找出一条点权最大的路径就行了,不限制点的个数。那么考虑对于一个环上的点被选择了,一整条环是不是应该都被选择,这一定很优,能选干嘛不选。很关键的是题目还允许我们重复经过某条边或者某个点,我们就不需要考虑其他了。因此整个环实际上可以看成一个点(选了其中一个点就应该选其他的点)
拓扑排序
对一个有向无环图(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的更多相关文章
- UVA 11324 The Largest Clique(缩点+DAG上的dp)
求最大团.和等价性证明有类似之处,只不过这个不是求互推,而是只要a->b,或b->a即可. 同样的,容易想到先缩点,得到DAG,每个节点上保存SCC的点数,相信任意一条由根节点(入度为零) ...
- BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]
方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...
- UVA - 10131Is Bigger Smarter?(DAG上的DP)
题目:UVA - 10131Is Bigger Smarter? (DAG) 题目大意:给出一群大象的体重和IQ.要求挑选最多的大象,组成一个序列.严格的体重递增,IQ递减的序列.输出最多的大象数目和 ...
- P2668 斗地主 dp+深搜版
题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4< ...
- 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 ...
- BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998 题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置 ...
- NYOJ16 矩形嵌套 【DAG上的DP/LIS】
矩形嵌套 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c ...
- DAG上的DP
引例:NYOJ16 矩形嵌套 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可 ...
- 洛谷 P2392 kkksc03考前临时抱佛脚, dp / 深搜
题目链接 P2392 kkksc03考前临时抱佛脚 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目 dp代码 #include <iostream> #includ ...
随机推荐
- The Preliminary Contest for ICPC Asia Xuzhou 2019 徐州网络赛 XKC's basketball team
XKC , the captain of the basketball team , is directing a train of nn team members. He makes all mem ...
- 题解 CF588A 【Duff and Meat】
题意 有一个人,想吃 $n$ 天肉,第 $i$ 天需要吃 $a[i]$ 块肉,第 $i$ 天超市肉价为每块 $b[i]$ 元,买来的肉可以留到后面吃,求这个人在每天都吃到肉的情况下花费的最小值. 题目 ...
- Vxlan L2
VXLAN(Virtual eXtensible LAN可扩展虚拟局域网)诞生了,基于IP网络之上,采用的是MAC in UDP技术 跨三层实现二层通信 总结为何需要Vxlan: 虚拟机规模受到网络规 ...
- http抓包—Content-Type讲解
1.Content-Type的定义 Content-Type(MediaType),即是Internet Media Type,互联网媒体类型,也叫做MIME类型.在互联网中有成百上千中不同的数据类型 ...
- opencv基于PCA降维算法的人脸识别
opencv基于PCA降维算法的人脸识别(att_faces) 一.数据提取与处理 # 导入所需模块 import matplotlib.pyplot as plt import numpy as n ...
- Halloween Costumes 玄学题
传送门 太难了,完全不懂 设\(dp[i][j]\)为第i天到第j天的最少代价 \(dp[i][j]=dp[i][j-1]+1\)(第j天多穿一件衣服) \(dp[i][j]=min(dp[i][j] ...
- 线段树 逆序对 Minimum Inversion Number HDU - 1394 Laptop
Minimum Inversion Number HDU - 1394 求最小反转数,就是求最少的逆序对. 逆序对怎么求,就是先把所有的数都初始化为0,然后按照顺序放入数字,放入数字前查询从这个数往后 ...
- F - Watching Fireworks is Fun
C. Watching Fireworks is Fun 题目大意: 一个城镇有n个区域,从左到右1-n,每个区域之间距离1个单位距离.节日中有m个烟火要放,给定放的地点a[ i ].时间t[ i ] ...
- dp 20190617
A. Alternative Thinking 这个标的是dp,但是我感觉就只能算思维题,不是特别难, 你仔细想想就知道,你先求出01这样子满足条件的个数,如果要进行改变,最多只可以增加两个,也可以增 ...
- 测试开发专题:spring-boot统一异常捕获
java异常介绍 异常时相对于return的一种退出机制,可以由系统触发,也可由程序通过throw语句触发,异常可以通过try/catch语句进行捕获并处理,如果没有捕获,则会导致程序退出并输出异常栈 ...