【luogu3387】 【模板】缩点 [tarjan 缩点]

P3387 【模板】缩点

静下心来去看 其实真的很好理解 突然搞不懂我之前为什么死活都看不懂

参悟了学长的代码还有BYVoid的讲解

放一下BYVoid大佬的tarjan伪代码 帮助理解

还有各种变量的含义 (from黄学长

栈里的元素表示的是当前已经访问过但是没有被归类到任一强连通分量的结点
dfn[u] 表示结点 u 在 DFS 中第一次搜索到的次序,通常被叫做时间戳
 ow[u] 它表示从 u 或者以 u 为根的子树中的结点,再通过一条反祖边或者横叉边可以到达的时间戳最小的结点 v 的时间戳,并且要求 v 有一些额外的性质:v 还要能够到达 u。
显然通过反祖边到达的结点 v 满足 low 的性质,但是通过横叉边到达的却不一定。

tarjan(u)
{
    DFN[u]=Low[u]=++Index                      // 为节点u设定次序编号和Low初值
    Stack.push(u)                              // 将节点u压入栈中
    for each (u, v) in E                       // 枚举每一条边
        if (v is not visted)               // 如果节点v未被访问过
            tarjan(v)                  // 继续向下找
            Low[u] = min(Low[u], Low[v])
        else if (v in S)                   // 如果节点v还在栈内
            Low[u] = min(Low[u], DFN[v])
    if (DFN[u] == Low[u])                      // 如果节点u是强连通分量的根
        repeat
            v = S.pop                  // 将v退栈,为该强连通分量中一个顶点
            print v
        until (u== v)
}

倒是看着学长的代码发现我并不理解vector

定义vector<int>G[maxn];G[i][j]表示以点i为起点连出的第j条边在边目录中的编号 图中加入一条边(u,v)则G[u].push_back(v); 遍历点u的邻接点只需遍历u的vector,然后根据u连出的边在边目录中的编号找到终点即可

然后就是后面的那个DAGdp有点点吃力 应该是我没认真理解题的原因

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int N=100000+5;
int n,m,dfn[N],low[N],inst[N],bl[N],idx=0,Bcnt=0;
int sum[N],val[N],dp[N];
stack<int>s;
vector<int>g[N];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch==‘-‘,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int head[N],tot=0;
struct edge{int u,v,nxt;}e[N];
void add(int u,int v){
    e[++tot]=(edge){u,v,head[u]};head[u]=tot;
}

void tarjan(int u){
    dfn[u]=low[u]=++idx;
    s.push(u);inst[u]=1;
    for(int i=head[u],v;i;i=e[i].nxt){
        v=e[i].v;
        if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
        else if(inst[v]&&dfn[v]<low[u]) low[u]=dfn[v];
    }
    if(dfn[u]==low[u]){
        int v;++Bcnt;
        do{
            v=s.top();s.pop();
            sum[Bcnt]+=val[v];
            bl[v]=Bcnt;
            inst[v]=0;
        }while(v!=u);
    }
}

int main(){
    rd(n),rd(m);
    memset(dfn,0,sizeof(dfn));
    for(int i=1;i<=n;++i) rd(val[i]);
    for(int i=1,u,v;i<=m;++i){
        rd(u),rd(v);
        add(u,v);
    }
    for(int i=1;i<=n;++i)
    if(!dfn[i]) tarjan(i);
    for(int i=1;i<=tot;++i)
    if(bl[e[i].u]!=bl[e[i].v]) g[bl[e[i].v]].push_back(bl[e[i].u]);
    //插入边(bl[v],bl[u])
    for(int i=Bcnt;i;--i){
        dp[i]=sum[i];
        for(int j=0;j<g[i].size();++j) dp[i]=max(dp[i],dp[g[i][j]]+sum[i]);
    }
    int ans=0;
    for(int i=1;i<=Bcnt;++i) ans=max(ans,dp[i]);
    printf("%d",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/lxyyyy/p/11008066.html

时间: 2024-10-14 21:45:58

【luogu3387】 【模板】缩点 [tarjan 缩点]的相关文章

tarjan缩点与割点

Tarjan算法 先是废话时间:说来挺惭愧 , 好几个月以前就学过tarjan算法然而现在才第一次写 模板题:[luogu P3387][模板]缩点 tarjan缩点&dp 为啥要缩点答案显然 把环缩成一个点 然后图上拓扑dp tarjan同名算法有很多 , 比如本blog的缩点与割点的tarjan算法其实并不是一个东西 , 但是很是相似 这个tarjan , 需要三个东西 第一:一个栈来存放搜到的点 第二:一个时间戳dfn , 表示第几个搜到这个点的 第三:low数组 , 表示够追溯到的最早的

模板:tarjan缩点+重新建边+最短路

洛谷P3387 [模板]缩点 题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次. 输入输出格式 输入格式: 第一行,n,m 第二行,n个整数,依次代表点权 第三至m+2行,每行两个整数u,v,表示u->v有一条有向边 输出格式: 共一行,最大的点权之和. 输入输出样例 输入样例#1: 复制 2 2 1 1 1 2 2 1 输出样例#1: 

[模板]tarjan缩点+拓扑排序

题目:给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次. 题目简述:先tarjan缩点,再从入度为零处进行一次拓扑排序,求最长路即可,话说拓扑排序求最长路真方便... 注意: 要明确拓扑的写法,要用栈写最优. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define man 100010 4 inline i

Tarjan缩点模板 (洛谷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^

【模板】缩点 tarjan+dp

题目背景 缩点+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^

tarjan缩点以及链式前向星的基本+应用(洛谷1262 间谍网络)

题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B.有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意交出手中掌握的全部情报.所以,如果我们能够收买一些间谍的话,我们就可能控制间谍网中的每一分子.因为一旦我们逮捕了一个间谍,他手中掌握的情报都将归我们所有,这样就有可能逮捕新的间谍,掌握新的情报. 我们的反间谍机关提供了一份资料,色括所有已知的受贿的间谍,以及他们愿意收受的具体数额.同时我们还知道哪些间谍手中具体掌握了哪些

tarjan+缩点+强连通定理

C - Network of Schools Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description A number of schools are connected to a computer network. Agreements have been developed among those schools: each school mai

洛谷 P2194 HXY烧情侣【Tarjan缩点】 分析+题解代码

洛谷 P2194 HXY烧情侣[Tarjan缩点] 分析+题解代码 题目描述: 众所周知,HXY已经加入了FFF团.现在她要开始喜(sang)闻(xin)乐(bing)见(kuang)地烧情侣了.这里有n座电影院,n对情侣分别在每座电影院里,然后电影院里都有汽油,但是要使用它需要一定的费用.m条单向通道连接相邻的两对情侣所在电影院.然后HXY有个绝技,如果她能从一个点开始烧,最后回到这个点,那么烧这条回路上的情侣的费用只需要该点的汽油费即可.并且每对情侣只需烧一遍,电影院可以重复去.然后她想花尽

初涉tarjan缩点

tarjan缩点:口胡过好多题,不过从来没写过…… 什么是缩点 tarjan和Kosaraju.Gabow算法一样,是为了求有向图中的强连通分量.因为有向图中大多数情况下会有环存在,而有环是一个不甚好的性质.如果把有向图里的所有强连通分量都看作是一个点(缩点),则原图就会变成一个DAG——DAG是一个好东西. 什么是tarjan缩点 tarjan算法网上大多有介绍,我也在之前看过多次,不过从未写过,这里不再介绍. 今天把核心代码重新看了一遍,终于深入理解了其算法.那么就不妨在这里直接放上代码.