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);
    }
  • 相关阅读:
    C# 中 Struct 与 Class 的区别,以及两者的适用场合<转转转>
    <转>.NET Framework十年回顾 体积越小功能越强
    一个数组,下标从0到n,元素为从0到n的整数。判断其中是否有重复元素
    在博客园已经一年多时间了,今天开通博客了!
    C#RSA非对称加解密
    无法向会话状态服务器发出会话状态请求请。确保 ASP.NET State Service (ASP.NET 状态服务)已启动
    JavaScript判断浏览器类型及版本(转)
    SQL Server 海量导入数据
    数据库管理方面必知语句(问答)(转)
    JS实现的购物车
  • 原文地址:https://www.cnblogs.com/ztz11/p/9810430.html
Copyright © 2011-2022 走看看