• P3387 【模板】缩点(Tarjan求强连通分量)


    题目背景

    缩点+DP

    题目描述

    给定一个 nnn 个点 mmm 条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

    允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

    输入格式

    第一行两个正整数 n,mn,mn,m

    第二行 nnn 个整数,依次代表点权

    第三至 m+2m+2m+2 行,每行两个整数 u,vu,vu,v,表示一条 u→vu ightarrow vuv 的有向边。

    输出格式

    共一行,最大的点权之和。

    输入输出样例

    输入 #1
    2 2
    1 1
    1 2
    2 1
    输出 #1
    2
    板子题因为脑瘫错误调了半天...
    注意到题干描述,很容易看出是要缩点,跑一遍Tarjan后我们就得到了一个DAG,DAG有点类似树的结构,只需要从每个入度为0的点(有点类似树根)跑dfs就行了,记得记忆化。
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 10005;
    const int M = 100005;
    int ver[M],Next[M],head[N],dfn[N]={0},low[N];
    int vc[M],nc[M],hc[N],tc=0;
    int sstack[N],ins[N],c[N];
    int point[N],point_c[N]={0};
    vector<int>scc[N];
    int n,m,tot=0,num=0,top=0,cnt=0;
    int ans[N]={0};
    void add(int x, int y)
    {
        ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
    }
    void add_c(int x,int y)
    {
        vc[++tc]=y,nc[tc]=hc[x],hc[x]=tc;
    }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++num;
        sstack[++top]=x,ins[x]=1;
        int i;
        for(i=head[x];i;i=Next[i])
        {
            if(!dfn[ver[i]])
            {
                tarjan(ver[i]);
                low[x]=min(low[x],low[ver[i]]);
            }
            else if(ins[ver[i]]) low[x]=min(low[x],dfn[ver[i]]);
        }
        if(dfn[x]==low[x])
        {
            cnt++;
            int y;
            do
            {
                y=sstack[top--],ins[y]=0;
                c[y]=cnt,scc[cnt].push_back(y);
            }while(x!=y);
        }
    }
    void dfs(int x,int pre)//得用缩点后的新图 
    {
        int i;
        ans[x]=max(ans[x],ans[pre]+point_c[x]);
        for(i=hc[x];i;i=nc[i])
        {
            if(vc[i]!=pre)dfs(vc[i],x);
        }
    }
    int main()
    {
        cin>>n>>m;
        int i,j,x;
        for(i=1;i<=n;i++)scanf("%d",&point[i]);
        for(i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        for(i=1;i<=n;i++)
        {
            if(!dfn[i])tarjan(i);
        } 
        int deg[N]={0}; 
        for(x=1;x<=n;x++)
        {
            for(i=head[x];i;i=Next[i])
            {
                int y=ver[i];
                if(c[x]==c[y])continue;
                add_c(c[x],c[y]);
                deg[c[y]]++;//deg表示入度 别写成deg[y]++ 
            }
        }
        for(i=1;i<=cnt;i++)
        {
            for(j=0;j<scc[i].size();j++)
            {
                point_c[i]+=point[scc[i][j]];
            }
        }
        //新图是一个有向无环图 找入度为0的点
        ans[0]=0;
        for(i=1;i<=cnt;i++)
        {
            
            if(deg[i]==0)//不能只从入度为0的点开始遍历 
            {
                dfs(i,0);
            }
        }
        int mmax=0;
        for(i=1;i<=cnt;i++)
        {
            mmax=max(mmax,ans[i]);
        }
        cout<<mmax<<endl;
        return 0;
    }
  • 相关阅读:
    axios 配置
    vue 配置App.js
    vue 挂载方式
    常用的js
    vuex
    vue搭建环境
    JS中 toString() & valueOf()
    html-webpack-plugin 中使用 title选项设置模版中的值无效
    webpack为什么加载不了css?
    visual studio for mac 安装文件
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12821112.html
Copyright © 2020-2023  润新知