• Luogu 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,点权<=1000

    算法:Tarjan缩点+DAGdp

     1 //2018年4月30日17:48:17
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 using namespace std;
     6 
     7 const int N = 100001;
     8 const int M = 500001;
     9 
    10 int n, m, w[N], ans;
    11 
    12 int fir[N], to[M], nxt[M], edge_num;
    13 void addEdge(int x, int y){
    14     to[++edge_num] = y;
    15     nxt[edge_num] = fir[x];
    16     fir[x] = edge_num; 
    17 }
    18 
    19 int dfn[N], low[N], stack[N], top, instack[N], tim, col_num, color[N], sum[N];
    20 void Tarjan(int x){
    21     low[x] = dfn[x] = ++tim;
    22     stack[++top] = x;
    23     instack[x] = 1;
    24     for(int i=fir[x]; i; i=nxt[i]){
    25         int v = to[i];
    26         if(!dfn[v]){
    27             Tarjan(v);
    28             low[x] = min(low[x], low[v]);
    29         }else if(instack[v]){
    30             low[x] = min(low[x], dfn[v]);
    31         }
    32     }
    33     if(low[x] == dfn[x]){
    34         col_num++;
    35         while(1){
    36             int now = stack[top--];
    37             instack[now] = 0;
    38             color[now] = col_num;
    39             sum[col_num] += w[now];
    40             if(now == x) break; 
    41         }
    42     }
    43 }
    44 
    45 int dp[N];
    46 
    47 int dfs(int u){
    48     if(dp[u]) return dp[u];
    49     dp[u] = sum[u];
    50     int mx = 0;
    51     for(int i=fir[u]; i; i=nxt[i]){
    52         int v = to[i];
    53         if(!dp[v]) dfs(v);
    54         if(dp[v] > mx) mx = dp[v]; 
    55     }
    56     dp[u] += mx;
    57     return dp[u];
    58 }
    59 
    60 int main(){
    61     scanf("%d%d", &n, &m);
    62     for(int i=1; i<=n; i++)
    63         scanf("%d", &w[i]);
    64     int x[N], y[N]; 
    65     for(int i=1; i<=m; i++){
    66         scanf("%d%d", &x[i], &y[i]);
    67         addEdge(x[i], y[i]); 
    68     }
    69     for(int i=1; i<=n; i++)
    70         if(!dfn[i])
    71             Tarjan(i);
    72     memset(fir, 0, sizeof(fir));
    73     memset(to, 0, sizeof(to));
    74     memset(nxt, 0, sizeof(nxt));
    75     edge_num = 0;
    76     for(int i=1; i<=m; i++)
    77         if(color[x[i]] != color[y[i]])
    78             addEdge(color[x[i]], color[y[i]]);
    79     for(int i=1; i<=col_num; i++)
    80         if(!dp[i]){
    81             dfs(i);
    82             ans = max(ans, dp[i]);
    83         }
    84     printf("%d
    ", ans);
    85 
    86     return 0;
    87 }
  • 相关阅读:
    UVALive 6044(双连通分量的应用)
    hdu 3760(2次bfs求最短路)
    zoj 3370(二分+二分图染色)
    sgu 326(经典网络流构图)
    hdu 4291(矩阵+暴力求循环节)
    uva 11381(神奇的构图、最小费用最大流)
    hdu 4685(匹配+强连通分量)
    hdu 4496(并查集)
    hdu 4722(记忆化搜索)
    Linux安装Nginx使用负载均衡
  • 原文地址:https://www.cnblogs.com/sineagle/p/8974235.html
Copyright © 2020-2023  润新知