P3387缩点(tarjan+拓扑排序+线性dp)
题目描述
给定一个 n个点 m 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
输入格式
第一行两个正整数 n,,m
第二行 n 个整数,依次代表点权
第三至 m+2行,每行两个整数 u,v,表示一条 u→v 的有向边。
输出格式
共一行,最大的点权之和。
题目链接:P3387
分析:相信大家已经看过题目了,在看我的题解之前也应该看过别的大佬的题解了(毕竟我是蒟蒻),虽然所有的题解一上来就会明确告诉你思路是tarjan+拓扑+dp,但为什么是这个思路确很少分析,我们不妨来分析一下加深自己的理解
对于这道题,要找出加权有向图中一条路径上最大的权值和sum(w),w我们第一时间想到是什么情况下sum(w)最大,第一反应是路径越长则sum(w)趋于越大,虽然极其的不严格,但却好比一根团绳子(一个图),表面上很难看出来哪一根最长,因为有折叠起来的部分(环),所以第一步要拆折叠为直线(tarjan缩点),在缩点后,有向图中的环消失,原图中的环被缩成了点.
好,现在折叠的部分被拆开了,图现在变成了有向无环图,路径清晰明确,是时候进行dp了,用dp来找出最优解(类似于最长上升子序列,在选与不选中抉择),但是想要进行dp,还要满足以下两个条件:
1.最优子结构.
2.无后效性.
对于最优子结构:我们规定,dp[i]为当dp到点i时的最优情况,那么dp[n]为最终的唯一解,设最后一次选取在点u->n之间,那么,要是dp[n]最大,有dp[n]=max(dp[n],dp[u]+w[n]);
证明:假设dp[u]不符合最优解,那么则必定存在有dp1[u]>dp[u],那么有dp1[n]=dp1[u]+w[v]>dp[u],这与dp[n]的最优性矛盾,因为在n时的dp[n]已经是唯一最优解.
然而对于无后效性,在某次dp时因为dp此时的图并不是严格线性的,合并前的状态有可能影响合并后的走向,比如遇到多出度的点,无法保证无后效性
那么这时就要用到拓扑排序,我个人的理解为,将一个有向无环图变为一个线性序列,在这个线性序列中,取任意两点u,v,如果从u->v出现在缩点后图的传递闭包中,那么在队列中u必然在v之前.
这时,dp变成了线性dp,无后效性轻松保证.
具体的算法实现
好,现在我们知道为什么要用这三样东西了,思路就变得清晰起来.首先对于tarjan,如果是从受欢迎的牛或者从其他强连通分量的题过来的小伙伴应该大致有一些了解.
在tarjan的过程中主要是动态的更新两个东西,dfn和low,代表着按时间上遍历到的顺序情况和够追溯到的最早的栈中节点的次序号,当dfn[u]==low[u]时,即某一次dfn时又指回了low[u],所以可以成环.
这里安利一下我的另一篇题解:P1262间谍网络
对于拓扑排序我一般写bfs(其他方法记不住,因为比较菜),具体思路为,找入度为0的点加入队列,然后删除该点的所有出度边,在次寻找,重复下去直至空图,类似于dijkstra,只不过这里找的是路径最大权值和.
那么废话就不多说了,上码
#include<bits/stdc++.h>
#define N 100005
using namespace std;
struct node
{
int next,to;
} e[N*];//原图
struct node1
{
int to,next;
}e1[N*];//缩点后的图
int head[*N],dfn[N*],low[N*];
int vis[N*],color[N*],sd[N*];
int w[*N],dp[N*];
int head1[N*];
int tim=,total,n,m,cnt,cnt1;
stack<int> q;
inline void add(int x,int y)
{
cnt++;
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt;
}
inline void add1(int x,int y)
{
cnt1++;
e1[cnt1].next=head1[x];
e1[cnt1].to=y;
head1[x]=cnt1;
}
void tarjan(int x)
{
dfn[x]=low[x]=tim;
tim++;
vis[x]=true;
q.push(x);
for(int i=head[x];i;i=e[i].next)
{
int u=e[i].to;
if(!dfn[u])
{
tarjan(u);
low[x]=min(low[x],low[u]);
}
else if(vis[u]) low[x]=min(low[x],dfn[u]);
}
if(low[x]==dfn[x])
{ total++;
int y;
do{
y=q.top();
q.pop();
vis[y]=false;
color[y]=total;
sd[total]+=w[y];
}while(x!=y);
}
}
int dijkstra(int x)
{
int sum=;
memset(dp,-0x3f,sizeof(dp));
memset(vis,false,sizeof(vis));
queue<int> Q;
Q.push(x);
vis[x]=true;
dp[x]=;
while(!Q.empty())
{
x=Q.front();
Q.pop();
vis[x]=false;
sum=max(sum,dp[x]+sd[x]);
for(int i=head1[x];i;i=e1[i].next)
{
int y=e1[i].to;
if(dp[y]<dp[x]+sd[x])
dp[y]=dp[x]+sd[x];
if(vis[y]) continue;
Q.push(y);
}
}
return sum;
}
int main()
{
cin>>n>>m;
for(int i=;i<=n;i++)
{
cin>>w[i];
}
for(int i=;i<=m;i++)
{
int x,y;
cin>>x>>y;
add(x,y);
}
for(int i=;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
for(int i=;i<=n;i++)
for(int j=head[i];j;j=e[j].next)
{
int v=e[j].to;
if(color[i]!=color[v])
{
add1(color[i],color[v]);
}
}
int ans=;
for(int i=;i<=total;i++)
{
ans=max(dijkstra(i),ans);
}
cout<<ans;
return ;
}
P3387缩点(tarjan+拓扑排序+线性dp)的更多相关文章
- 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp
题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:对于u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. ...
- 【模拟7.16】通讯(tarjan缩点加拓扑排序)
这题确实水,纯板子,考试意外出错,只拿了暴力分QAQ tarjan缩点加上拓扑排序,注意这里求最短路径时不能用最小生成树 因为是单向边,不然就可能不是一个联通图了.... 1 #include< ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
- 【Luogu P3387】缩点模板(强连通分量Tarjan&拓扑排序)
Luogu P3387 强连通分量的定义如下: 有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶 ...
- 【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP
1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 787 Solved: 318[Submit][Stat ...
- bzoj1093[ZJOI2007]最大半连通子图(tarjan+拓扑排序+dp)
Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u ...
- 【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图
思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于 ...
- 洛谷P1073 Tarjan + 拓扑排序 // 构造分层图
https://www.luogu.org/problemnew/show/P1073 C国有 n n个大城市和 mm 条道路,每条道路连接这 nn个城市中的某两个城市.任意两个城市之间最多只有一条道 ...
- bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划
一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V ...
随机推荐
- DZNEmptyDataSet框架阅读
前段时间使用公司封装的空白页占位视图工具,工具是对DZNEmptyDataSet框架的封装.这个框架以前在许多项目也都用过,却没有认真阅读过源码,真的很遗憾.这两天趁五一放假有空,将DZNEmpt ...
- 程序员如何才能跨过高级级别,譬如腾讯T3.1/阿里P7
首先自我介绍下自己履历:5年前过了腾讯的T3.2,最近又在1年多前过了阿里的P8,目前在B站. **腾讯** 在腾讯我是T2.1社招一般水平入职的,3年后到了T3.2.中间是经历过几个转变:刚来的半年 ...
- Springboot引入本地jar时打包
在项目的开发过程中有时我们需要引入我们本地的jar包,这些jar包没有存在maven仓库中 ,这时没有办法通过pom文件直接引入,在开发过程中我们可以通过add as library的方式,可以在开发 ...
- KMO检验和Bartlett球形检验
KMO检验和Bartlett球形检验因子分析前,首先进行KMO检验和巴特利球体检验,KMO检验系数>0.5,(巴特利特球体检验的x2统计值的显著性概率)P值<0.05时,问卷才有结构效度, ...
- 【红外DDE算法】聊聊红外图像增强算法的历史进程(第一回)
宽动态红外图像增强算法综述回顾过去带你回顾宽动态红外图像增强算法的历史进程,历来学者的一步步革命(新的算法框架提出),一步步改革(改进优化),从简单粗暴到细致全面.正所谓是:改革没有完成时,只有进行时 ...
- (分块)Holes CodeForces - 13E
题意 n(n≤105)个洞排成一条直线,第ii个洞有力量值ai,当一个球掉进洞ii时就会被立刻弹到i+ai,直到超出n.进行m(m≤105)次操作: ·修改第i个洞的力量值ai. ·在洞xx上放一个球 ...
- 【python系统学习07】一张图看懂字典并学会操作
点击跳转 - 原文地址 数据类型 - 字典(dict) 目录: 一张图get字典 字典是什么 js的对象 字典长啥样 语法伪代码 示例demo 语法成像 字典怎么用 字典长度获取--len函数 提取字 ...
- 关于PDF阅读器
获取流程 1.点击下载xodo 2.跳转到如下界面,单击箭头所指的版本: 3.单击转到 中国-中文 4.点击获取 5.在跳出来的界面点击红框 6.打开本机的Microsoft Store下载应用 介绍 ...
- typescript step by step
如果有本 typescript的书 这个名字不错 啊 step one
- C#反射与特性(四):实例化类型
目录 1,实例化类型 1.1 Activator.CreateInstance() 1.2 ConstructorInfo.Invoke() 2,实例化委托 3,实例化泛型类型 3.1 实例化泛型 3 ...