• 洛谷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
  • 相关阅读:
    自动化测试工具Gauge--contexts 与 Tear Down steps
    Redis官网第一次闲逛
    针对 《Linux就该这么学》 之 “第三章---管道符、重定向、环境变量” 摘抄、操练及拓展
    父shell 和 子shell; shell脚本的几种执行方式
    麒麟操作系统操练Linux基操
    HTTP代理
    gcc/g++ 安全编码
    golang 生成rsa秘钥对
    depth of feild
    Emission pass
  • 原文地址:https://www.cnblogs.com/zk1431043937/p/7801060.html
Copyright © 2020-2023  润新知