zoukankan      html  css  js  c++  java
  • Luogu3387 缩点 【tarjan】【DP】

    Luogu3387 缩点


    题目背景

    缩点+DP

    题目描述

    给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
    允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

    输入格式:

    第一行,n,m
    第二行,n个整数,依次代表点权
    第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

    输出格式:

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

    输入样例:

    2 2
    1 1
    1 2
    2 1

    输出样例:

    2

    说明

    n<=10^4,m<=10^5,点权<=1000


    挺板子的一道题,敲它主要是因为最近爱上了封装科技
    虽然题面没有说,不过这道题的数据好像没有涉及到负数,不然还有点麻烦
    直接把原图tarjan缩点然后DAG上面DP就好了
    小技巧:如果不想考虑缩点之后两个点之间有多条边的情况,直接记忆化搜索就好了


    //yangkai
    #include<bits/stdc++.h>
    using namespace std;
    #define N 100010
    int m,ans=0,ru[N],f[N];
    struct Edge{int u,v,next;};
    struct G{
        Edge E[N];
        int head[N],val[N],tot,siz;//siz:节点个数
        G(){
            tot=0;
            memset(head,0,sizeof(head));
            memset(val,0,sizeof(val));
        }
        void add(int u,int v){
            E[++tot]=(Edge){u,v,head[u]};
            head[u]=tot;
        }
    }g1,g2;
    struct Tarjan{
        G g;
        int dfn[N],low[N],belong[N],index,cnt;
        bool vis[N];
        stack<int> s;
        Tarjan(){index=cnt=0;}
        void tarjan(int u){
            vis[u]=1;s.push(u);
            dfn[u]=low[u]=++index;
            for(int i=g.head[u];i;i=g.E[i].next){
                int v=g.E[i].v;
                if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
                else if(vis[v])low[u]=min(low[u],dfn[v]);
            }
            if(low[u]==dfn[u]){
                int v;cnt++;
                do{
                    v=s.top();s.pop();
                    belong[v]=cnt;
                    vis[v]=0;
                }while(v!=u);
            }
        }
        void tarjan(){
            for(int i=1;i<=g.siz;i++)
                if(!dfn[i])tarjan(i);
        }
    }tar;
    int dfs(int u){//记忆化搜索部分
        if(f[u])return f[u];
        for(int i=g2.head[u];i;i=g2.E[i].next){
            int v=g2.E[i].v;
            f[u]=max(f[u],dfs(v));
        }
        return f[u]+=g2.val[u];
    }
    int main(){
        scanf("%d%d",&g1.siz,&m);
        for(int i=1;i<=g1.siz;i++)scanf("%d",&g1.val[i]);
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            g1.add(u,v);
        }
        tar.g=g1;
        tar.tarjan();
        for(int i=1;i<=g1.siz;i++)
        g2.siz=tar.cnt;
        for(int i=1;i<=g1.siz;i++)g2.val[tar.belong[i]]+=g1.val[i];
        for(int i=1;i<=m;i++)if(tar.belong[g1.E[i].u]!=tar.belong[g1.E[i].v])
            g2.add(tar.belong[g1.E[i].u],tar.belong[g1.E[i].v]),ru[tar.belong[g1.E[i].v]]=1;
        for(int i=1;i<=g2.siz;i++)if(!ru[i])ans=max(ans,dfs(i));//考虑可能有多个入入度为0的点
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    《基于Android的大学学生信息查询系统设计与实现》论文笔记(十二)
    《课程安排管理系统分析与设计》论文笔记(十一)
    第十次读书笔记 软件工程:方法与实践
    结对作业收获_core组
    软件工程:方法与实践 第七次读书笔记
    结对作业_core组
    软件工程:方法与实践 第六次读书笔记
    第五周课后作业
    软件工程 :方法与实践 第五次读书笔记
    个人作业—词频统计
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9676395.html
Copyright © 2011-2022 走看看