zoukankan      html  css  js  c++  java
  • 洛谷P3387 【模板】缩点

    洛谷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

    题解:模板缩点,马上就要NOIP了,当作复习一下。

    缩点的思想是找到一个环,把这个环缩成一个点。若原图联通,则缩点并不影响环外的连通性。

    因此对于这题,我们把环缩成点时,环内所有的点的权值和为新点的权值,然后从所有入度为零的点作为起点跑一边SPFA就能求得单向路径上的最大值。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<queue>
     5 #include<stack>
     6 using namespace std;
     7 const int N=10005,M=100005;
     8 int n,m,x,y,cnt,tot,ans,a[N],p[N],fro[M],to[M],nxt[M],head[N];
     9 int Cnt,To[M],Nxt[M],Head[M],deg[N],dfn[N],low[N],grp[N],dis[N];
    10 bool vis[N],mark[N];
    11 queue<int> Q;
    12 stack<int> S;
    13 void add(int u,int v){
    14     fro[++cnt]=u; to[cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    15 }
    16 void Add(int u,int v){
    17     To[++Cnt]=v; Nxt[Cnt]=Head[u]; Head[u]=Cnt;
    18 }
    19 void Tarjan(int u)
    20 {
    21     vis[u]=mark[u]=1; S.push(u); dfn[u]=low[u]=++tot;
    22     for (int i=head[u];i;i=nxt[i])
    23     {
    24         int v=to[i];
    25         if (!dfn[v])
    26         {
    27             Tarjan(v);
    28             low[u]=min(low[u],low[v]);
    29         }
    30         if (mark[v]) low[u]=min(low[u],dfn[v]);
    31     }
    32     if (low[u]==dfn[u])
    33     {
    34         ++tot;
    35         int x=S.top();
    36         while (x!=u)
    37         {
    38             grp[x]=tot;
    39             p[tot]+=a[x];
    40             mark[x]=0;
    41             S.pop();
    42             x=S.top();
    43         }
    44         grp[x]=tot;
    45         p[tot]+=a[x];
    46         mark[x]=0;
    47         S.pop();
    48     }
    49 }
    50 void SPFA(int x)
    51 {
    52     ans=max(ans,p[x]);
    53     memset(vis,0,sizeof(vis));
    54     memset(dis,0,sizeof(dis));
    55     Q.push(x); dis[x]=p[x]; vis[x]=1;
    56     while (!Q.empty())
    57     {
    58         int u=Q.front(); Q.pop(); vis[u]=0;
    59         for (int i=Head[u];i;i=Nxt[i])
    60         {
    61             int v=To[i];
    62             if (dis[u]+p[v]>dis[v])
    63             {
    64                 dis[v]=dis[u]+p[v];
    65                 ans=max(ans,dis[v]);
    66                 if (!vis[v]) vis[v]=1,Q.push(v);
    67             }
    68         }
    69     }
    70 }
    71 int main()
    72 {
    73     scanf("%d%d",&n,&m);
    74     for (int i=1;i<=n;++i) scanf("%d",&a[i]);
    75     for (int i=1;i<=m;++i) scanf("%d%d",&x,&y),add(x,y);
    76     for (int i=1;i<=n;++i) if (!vis[i]) Tarjan(i);
    77     for (int i=1;i<=m;++i)
    78     {
    79         if (grp[fro[i]]!=grp[to[i]])
    80         {
    81             Add(grp[fro[i]],grp[to[i]]);
    82             ++deg[grp[to[i]]];
    83         }
    84     }
    85     for (int i=1;i<=tot;++i) if (!deg[i]) SPFA(i);
    86     printf("%d
    ",ans);
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    (二分查找 拓展) leetcode 69. Sqrt(x)
    (二分查找 拓展) leetcode 162. Find Peak Element && lintcode 75. Find Peak Element
    (链表) lintcode 219. Insert Node in Sorted Linked List
    (二分查找 拓展) leetcode 34. Find First and Last Position of Element in Sorted Array && lintcode 61. Search for a Range
    (最短路 Floyd) P2910 [USACO08OPEN]寻宝之路Clear And Present Danger 洛谷
    (字符串 数组 递归 双指针) leetcode 344. Reverse String
    (二叉树 DFS 递归) leetcode 112. Path Sum
    (二叉树 DFS 递归) leetcode 101. Symmetric Tree
    (二叉树 递归) leetcode 144. Binary Tree Preorder Traversal
    (二叉树 递归 DFS) leetcode 100. Same Tree
  • 原文地址:https://www.cnblogs.com/zk1431043937/p/7801060.html
Copyright © 2011-2022 走看看