当前位置: 首页 > news >正文

【模板】缩点

洛谷p3387
思路:
算法:tarjan算法

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

  

}

相关文章:

  • GPU算力优化
  • 敏感词过滤算法
  • swift菜鸟教程1-5(语法,变量,类型,常量,字面量)
  • centos7.9 升级 gcc
  • 杂 题 (日常练习)
  • 【千问大模型API申请教程】
  • VitePress 项目部署 cloudflare page 提示 npm run build 错误
  • 简明使用pybind11开发pythonc++扩展模块教程
  • 《高绩效教练》(第5版)第二部分第4章总结
  • LeetCode.2999. 统计强大整数的数目
  • SAP系统控制检验批
  • 多模态人工智能:从感知到认知的跨越
  • 操作系统 3.1-内存使用和分段
  • BeeWorks:高效协作的局域网聊天工具
  • 《Vue Router实战教程》21.扩展 RouterLink
  • 设计模式 四、行为设计模式(2)
  • 苍穹外卖2
  • 算法训练之动态规划(四)——简单多状态问题
  • AutoEval:现实世界中通才机器人操作策略的自主评估
  • 电机控制储备知识 四:电机的分类
  • 多商户商城系统源码/泉州关键词优化报价
  • 高端网站建设定制/论坛外链代发
  • 门户网站的三大基本特征/sem账户托管外包
  • 扬州网站建设费用/活动推广方案策划
  • 网站建设如何建/中国十大策划公司排名
  • 自建购物网站/沈阳百度快照优化公司