zoukankan      html  css  js  c++  java
  • 洛谷 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 } 
  • 相关阅读:
    windows安装nacos
    anki处理
    minikube安装net5
    在.net core中使用属性注入
    C# 使用MD5算法对密码进行加密
    c# 获取本机系统已经安装的打印机信息
    C# 比较两个datatable并找出修改差异的值
    打印机点击打印后无反应
    GUID转换成16位字符串或19位数据(确保唯一)
    RESTful
  • 原文地址:https://www.cnblogs.com/zjzjzj/p/11334318.html
Copyright © 2011-2022 走看看