• 洛谷 P3387 【模板】缩点


    题目

    题目背景

    缩点+DP

    题目描述

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

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

    输入格式

    第一行,n,m

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

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

    输出格式

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

    输入输出样例

    输入 #1
    2 2
    1 1
    1 2
    2 1
    输出 #1
    2

    说明/提示

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

    算法:Tarjan缩点+DAGdp

     

    分析

     

    • tarjan模板,因为经过点可以重复,但是权值只能纪录一次
    • 那么我们将环缩成一个点
    • 然后直接跑记忆化
    • 找到最大值就好了

     

    代码

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 struct sb
     5 {
     6     int to,nx;
     7 }g[200001];
     8 int x[100001],y[100001],t[100001];
     9 int cnt,list[200001];
    10 void add(int x,int y)
    11 {
    12     g[++cnt].to=y; g[cnt].nx=list[x]; list[x]=cnt;
    13 }
    14 int dfn[100001],low[100001],num,stack[100010],top,color[100010],col,sum[100010],vis[100010];
    15 void tarjan(int x)
    16 {
    17     dfn[x]=++num;
    18     low[x]=num;
    19     vis[x]=1;
    20     stack[++top]=x;
    21     for (int i=list[x];i;i=g[i].nx)
    22     {
    23         int y=g[i].to;
    24         if (!dfn[y])
    25         {
    26             tarjan(y);
    27             low[x]=min(low[x],low[y]);
    28         }
    29         else if (vis[y]) low[x]=min(low[x],dfn[y]);
    30     }
    31     if (dfn[x]==low[x]) 
    32     {
    33         ++col;
    34         while (stack[top+1]!=x)
    35         {
    36             color[stack[top]]=col;
    37             sum[col]+=t[stack[top]];
    38             vis[stack[top--]]=false;
    39         }
    40     }
    41 }
    42 int f[100010];
    43 void dfs(int x)
    44 {
    45     if (f[x]) return;
    46     f[x]=sum[x];
    47     int maxsum=0;
    48     for (int i=list[x];i;i=g[i].nx)
    49     {
    50         int y=g[i].to;
    51         if (!f[y]) dfs(y);
    52         maxsum=max(maxsum,f[y]);
    53     }
    54     f[x]+=maxsum;
    55 }
    56 int main ()
    57 {
    58     int n,m;
    59     cin>>n>>m;
    60     for (int i=1;i<=n;i++) cin>>t[i];
    61     for (int i=1;i<=m;i++)
    62     {
    63         cin>>x[i]>>y[i];
    64         add(x[i],y[i]);
    65     }
    66     for (int i=1;i<=n;i++)
    67       if (!dfn[i]) tarjan(i);
    68     memset(g,0,sizeof(g));
    69     memset(list,0,sizeof(list));
    70     cnt=0;
    71     for (int i=1;i<=m;i++)
    72        if (color[x[i]]!=color[y[i]])
    73          add(color[x[i]],color[y[i]]);
    74     int ans=0;
    75     for (int i=1;i<=col;i++)
    76       if (!f[i])
    77       {
    78            dfs(i);
    79            ans=max(ans,f[i]);
    80       }
    81     cout<<ans;
    82     
    83 } 
  • 相关阅读:
    C#中直接调用VB.NET的函数,兼论半角与全角、简繁体中文互相转化<收藏>
    C# Passing Associative Arrays to PL/SQL Code
    Executing a PL/SQL Function
    一个oracle 学习网站 收藏
    C# Retrieving Associative Arrays from PL/SQL Code
    向oracle 数据库写入 LOBs 数据
    Oracle 11g如何赢得.NET开发人员的青睐?
    使用C#进行Reflection编程
    反射(Reflection
    四种简单的排序算法
  • 原文地址:https://www.cnblogs.com/zjzjzj/p/11334318.html
Copyright © 2020-2023  润新知