【模板】缩点

洛谷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();

  

}
相关推荐
yi0113 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
灯澜忆梦5 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下5 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J6 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛6 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有7 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode
aqiu1111117 小时前
【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
c++·算法·leetcode
黄金龙PLUS7 小时前
如何基于置换算法来设计对称加密算法
算法·网络安全·密码学·哈希算法·同态加密
不会就选b7 小时前
算法日常・每日刷题--<动态规划>14
算法
赛博守夜人7 小时前
跨境业务与出海合规之九:海外买量投放与营销虚假流量(Ad Fraud):跨国机房群控与归因欺诈识别算法
算法·安全