zoukankan      html  css  js  c++  java
  • 【模板】缩点(tarjan,DAG上DP)

    题目背景

    缩点+DP

    题目描述

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

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

    输入输出格式

    输入格式:

    第一行,n,m

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

    第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

    输出格式:

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

    思路:

    显然,由于点权为正,所以位于一个强连通分量中的结点,自然走得越多答案越大

    所以,我们可以跑一边tarjan,将所有的强连通分量染色,建一个新的图

    其中新图上的每个结点都代表旧图上的一个强连通分量

    在跑tarjan染色的同时我们可以累加得到新图上每个点的点权

    最后在新图上跑一边DP或者记忆化搜索即可

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define rii register int i
    #define rij register int j
    using namespace std;
    struct yb{
        int from,to;
    }y[100005];
    struct ljb{
        int to,nxt;
    }x[100005];
    int tot,dq[10005],sta[10005],sum[10005],head[10005],bnt,last[10005];
    int n,m,dfn[10005],low[10005],top,cnt,vis[10005],color[10005],dp[10005];
    void add(int from,int to)
    {
        bnt++;
        x[bnt].to=to;
        if(head[from]==0)
        {
            head[from]=bnt;
        }
        if(last[from]!=0)
        {
            x[last[from]].nxt=bnt;
        }
        last[from]=bnt;
    }
    void search(int wz)
    {
        if(dp[wz]!=0)
        {
            return;
        }
        dp[wz]=sum[wz];
        int maxn=0;
        for(rii=head[wz];i!=0;i=x[i].nxt)
        {
            int ltt=x[i].to;
            if(dp[ltt]==0)
            {
                search(ltt);
            }
            maxn=max(maxn,dp[ltt]);
        }
        dp[wz]+=maxn;
    }
    void tarjan(int wz)
    {
        cnt++;
        low[wz]=cnt;
        dfn[wz]=cnt;
        top++;
        sta[top]=wz;
        vis[wz]=1;
        for(rii=head[wz];i!=0;i=x[i].nxt)
        {
            int ltt=x[i].to;
            if(dfn[ltt]==0)
            {
                tarjan(ltt);
                low[wz]=min(low[wz],low[ltt]);
            }
            else
            {
                if(vis[ltt]==1)
                {
                    low[wz]=min(low[wz],dfn[ltt]);
                }
            }
        }
        if(dfn[wz]==low[wz])
        {
            tot++;
            while(sta[top+1]!=wz)
            {
                color[sta[top]]=tot;
                sum[tot]+=dq[sta[top]];
                vis[sta[top]]=0;
                top--;
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(rii=1;i<=n;i++)
        {
            scanf("%d",&dq[i]);
        }
        for(rii=1;i<=m;i++)
        {
            scanf("%d%d",&y[i].from,&y[i].to);
            add(y[i].from,y[i].to);
        }
        for(rii=1;i<=n;i++)
        {
            if(dfn[i]==0)
            {
                tarjan(i);
            }
        }
    /*
        for(rii=1;i<=n;i++)
        {
            printf("%d ",color[i]);
        }
        cout<<endl;
        */
        bnt=0;
        memset(head,0,sizeof(head));
        memset(last,0,sizeof(last));
        memset(x,0,sizeof(x));
        for(rii=1;i<=m;i++)
        {
            if(color[y[i].from]!=color[y[i].to])
            {
                add(color[y[i].from],color[y[i].to]);
            }    
        }
        int ans=0;
        for(rii=1;i<=n;i++)
        {
            if(dp[i]==0)
            {
                search(i);
            }
            ans=max(ans,dp[i]);
        }
        printf("%d
    ",ans);
    }
  • 相关阅读:
    解决Shockwave flash在chrome浏览器上崩溃的问题
    Java实现平衡二叉树(AVLTree)的构建
    Netty4具体解释二:开发第一个Netty应用程序
    cocos2dx实现android的对讯飞语音的合成(语言朗读的实现)
    how tomcat works 读书笔记四 tomcat的默认连接器
    我的职业观
    学习NodeJS第一天:node.js引言
    数学之路-python计算实战(20)-机器视觉-拉普拉斯算子卷积滤波
    .net web 开发平台- 表单设计器 一(web版)
    白话经典算法系列之中的一个 冒泡排序的三种实现
  • 原文地址:https://www.cnblogs.com/ztz11/p/9810430.html
Copyright © 2011-2022 走看看