• 【模板】缩点


       Tarjan算法的一个重要应用就是缩点。

    放上题目

    题目背景

    缩点+DP

    题目描述

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

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

    输入输出格式

    输入格式:

    第一行,n,m

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

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

    输出格式:

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

      Input

    2 2
    1 1
    1 2
    2 1
    Output
    2

    说明

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

    算法:Tarjan缩点+DAGdp


    这道题,在我看来,其实与Tarjan并无区别。

      缩点,算法就是名字啊。其意在于将一个环(强连通分量)当做一个点来处理。

      所以我们采用Tarjan求出所有的强连通分量,然后建出DAG(缩点)。

      最后再在建出的新图上面进行DP记搜,找到点权最大的就好了啊。


    放上代码。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 using namespace std;
     8 
     9 const int Ma=1e4+5;
    10 int n,m,val[Ma];
    11 int head[Ma],ecnt;
    12 int dfn[Ma],low[Ma],ti;
    13 int sk[Ma],p;
    14 bool vis[Ma];
    15 int in[Ma],dis[Ma];
    16 struct ss{
    17     int nxt,to;
    18     int self;
    19 }d[Ma*10];
    20 int fa[Ma];
    21 queue<int> q;
    22 
    23 void add(int a,int b) {
    24     d[++ecnt].to=b;
    25     d[ecnt].self=a;
    26     d[ecnt].nxt=head[a];
    27     head[a]=ecnt;
    28 }
    29 
    30 void Tar(int now) {
    31     dfn[now]=low[now]=++ti;
    32     sk[++p]=now;
    33     vis[now]=1;
    34     for(int i=head[now];i;i=d[i].nxt) {
    35         int nx=d[i].to;
    36         if(!dfn[nx]) {
    37             Tar(nx);
    38             low[now]=min(low[now],low[nx]);
    39         }
    40         else if(vis[nx]) low[now]=min(low[now],dfn[nx]);
    41     }
    42     if(low[now]==dfn[now]) {
    43         while(sk[p+1]!=now) {
    44             val[now]+=val[sk[p]];
    45             fa[sk[p]]=now;
    46             vis[sk[p]]=0;
    47             --p;
    48         }
    49         val[now]>>=1;
    50     }
    51 }
    52 
    53 void po() {
    54     for(int i=1;i<=n;i++)
    55         if(fa[i]==i) {
    56             dis[i]=val[i];
    57             if(!in[i]) q.push(i);
    58         }
    59     while(!q.empty()) {
    60         int now=q.front();
    61         for (int i=head[now];i;i=d[i].nxt) {
    62             int nxt=d[i].to;
    63             dis[nxt]=max(dis[nxt],dis[now]+val[nxt]);
    64             in[nxt]--;
    65             if(!in[nxt]) q.push(nxt);
    66         }
    67         q.pop();
    68     }
    69     return;
    70 }
    71 
    72 int main()
    73 {
    74     scanf("%d%d",&n,&m);
    75     for(int i=1;i<=n;i++) scanf("%d",&val[i]);
    76     for(int i=1;i<=m;i++) {
    77         int a,b;
    78         scanf("%d%d",&a,&b);
    79         add(a,b);
    80     }
    81     for(int i=1;i<=n;i++)
    82         if(!dfn[i]) Tar(i);
    83     ecnt=0;
    84     memset(head,0,sizeof head);
    85     for(int i=1;i<=m;i++) {
    86         int x=fa[d[i].self];
    87         int y=fa[d[i].to];
    88         if(x!=y) {
    89             add(x,y);
    90             in[y]++;
    91         }
    92     }
    93     po();
    94     int ans=0;
    95     for(int i=1;i<=n;i++)
    96         if(fa[i]==i) ans=max(ans,dis[i]);
    97     cout<<ans<<endl;
    98     return 0;
    99 }

      完成!可以静候AC了。

        

      你们这题可以用个快读,稍微优化优化,然后就.......

        

    祝AC愉快!

    ---OI是信仰,是真正应该被认真以待的东西.....!
  • 相关阅读:
    Java开发常用Util工具类
    冒泡排序
    EMQ 消息服务器
    将jar文件包打成exe文件
    mina框架搭建tcp服务器:编写自定义协议及编解码器
    SpringBoot中定时任务的设置
    SpringBoot项目+Shiro(权限框架)+Redis(缓存)集成
    计算两个时间之间的天数
    关于extern的使用
    ADC采样间隔问题+TRGO作为ADC的触发源头
  • 原文地址:https://www.cnblogs.com/qxyzili--24/p/10495386.html
Copyright © 2020-2023  润新知