【模板】缩点

洛谷p3387

思路:

算法:tarjan算法

复制代码
根据题意,我们只要找到一个路径,使得最终权重最大即可,首先,根据题目可知,如果一个点在一个环上,那么我们就将这整个环都选上,题目上允许我们能够重复走,因此,我们可以将环缩成点,将环所称点后,就可以转换成树,从没有父节点的结点开始,我们向下走,每遍历一个子结点,就将子节点更新一次,最终取结点的最大值即可
cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

int n,m;

const int N=1e4+19;

const int M=1e5+10;

vector<int>vec[N];

int a[N];

int siz[N];

int cnt;

int dfn[N],low[N],tot;

int p[N];

int scc[N];

int inDegree[N];

stack<int>sta;

//tarjan模板  

void tarjan(int x){

    low[x]=dfn[x]=++tot;

    sta.push(x);

    for(auto y:vec[x]){

        if(dfn[y]==0){

            tarjan(y);

            low[x]=min(low[x],low[y]);

        }else if(!scc[y]){

            low[x]=min(low[x],dfn[y]);

        }

    }

    if(low[x]==dfn[x]){

        cnt++;

        while(1){

            int y=sta.top();

            sta.pop();

            siz[cnt]++;

            p[cnt]+=a[y];//记录每个环的总权重

            scc[y]=cnt;

            if(y==x)break;

        }

    }

}

  

struct edge{

    int from;

    int to;

}e[M];

  
  

vector<int>ve[N];

  
  
  

int ans[N];

  
  

int s;

int res=0;

//topo算法
void solve(){

    queue<int>q;

    for(int i=1;i<=cnt;i++){

        ans[i]=p[i];
 //寻找没有入读的环
        if(!inDegree[i])q.push(i);

    }

    while(q.empty()==false){

        int x=q.front();

        q.pop();

        for(auto y:ve[x]){
//从没有入度的环开始,向下遍历它出度的环
//入度的环的最大值等于指向它的环的最大值加上它自己的权重
            ans[y]=max(ans[y],p[y]+ans[x]);
//处理一个入度的边就减去一个边
            inDegree[y]--;
//如果入度的点最终没有边指向它,那么代表它就成了一个根结点,那么,就将他放入队列中
            if(inDegree[y]==0)q.push(y);

        }

    }

    for(int i=1;i<=cnt;i++){

        res=max(res,ans[i]);

    }

    cout<<res<<endl;

}

  

int main(void){

    cin>>n>>m;

    for(int i=1;i<=n;i++)cin>>a[i];

    for(int i=1;i<=m;i++){

        int a,b;

        cin>>a>>b;
//记录边的原因是为了后序我们进行环与环的入度操作时候,可以直接遍历边
        e[i].from=a;

        e[i].to=b;

        vec[a].push_back(b);

    }

    for(int i=1;i<=n;i++){

        if(!dfn[i])tarjan(i);

    }

    for(int i=1;i<=m;i++){
//记入环与环之间相连的边
        int fr=scc[e[i].from];

        int tr=scc[e[i].to];

        if(fr==tr)continue;
//记入入度的边
        inDegree[tr]++;

        ve[fr].push_back({tr});

    }

    solve();

  

}
相关推荐
京东零售技术2 小时前
扛起技术大梁的零售校招生们 | 1024技术人特别篇
算法
爱coding的橙子2 小时前
每日算法刷题Day78:10.23:leetcode 一般树7道题,用时1h30min
算法·leetcode·深度优先
Swift社区2 小时前
LeetCode 403 - 青蛙过河
算法·leetcode·职场和发展
地平线开发者2 小时前
三种 Badcase 精度验证方案详解与 hbm_infer 部署实录
算法·自动驾驶
papership3 小时前
【入门级-算法-5、数值处理算法:高精度的减法】
算法·1024程序员节
lingran__3 小时前
算法沉淀第十天(牛客2025秋季算法编程训练联赛2-基础组 和 奇怪的电梯)
c++·算法
DuHz3 小时前
基于MIMO FMCW雷达的二维角度分析多径抑制技术——论文阅读
论文阅读·物联网·算法·信息与通信·毫米波雷达
Dragon_D.3 小时前
排序算法大全——插入排序
算法·排序算法·c·学习方法
大数据张老师4 小时前
数据结构——红黑树
数据结构·算法·红黑树
自在极意功。4 小时前
动态规划核心原理与高级实战:从入门到精通(Java全解)
java·算法·动态规划·最优子结构·重叠子问题