zoukankan      html  css  js  c++  java
  • 2019/5/13 洛谷P4742 【tarjan缩点 + 拓扑dp】

    题目链接:https://www.luogu.org/problemnew/show/P4742

    题目大意:给一张有向图, 每个点都有点权,第一次经过该点时,该点的点权有贡献,求这张图上一条路径(终点随意)的贡献最大并且得到该路径上一个最大点权。

    思路:

    1.值得注意的是,这里并不是求最长路,也就是并不是求最多的点组成的路径,点可以少,但是必须点权和最大。

    2.因为需要得到最大点权和以及最大点权,终点又不定,所以我们需要遍历图中每个点,来得到起点到该点的点权和以及路径上的最大点权。

    3.先用tarjan进行缩点处理, 若不这样直接遍历原图非常耗时。缩点的‘点’中需要记录的信息是每个连通分量中点的权值和以及最大的点权。

    4.还需要选择一个合理的遍历新图的方式, 那么选用 拓扑排序 ,(拓扑排序只有在设置汇点跳出的情况下得到的路径才不唯一,否则会根据点边关系遍历图中的每个点

    代码:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<stack>
      4 #include<queue>
      5 #include<algorithm>
      6 #define mem(a, b) memset(a, b, sizeof(a))
      7 using namespace std;
      8 const int inf = 0x3f3f3f3f;
      9 const int maxn = 200010;
     10 const int maxm = 500010;
     11 typedef long long ll;
     12 
     13 int n, m, in[maxn];
     14 int arr[maxn], max_node[maxn], sum_color[maxn];
     15 int cnt, new_cnt, head[maxn], new_head[maxn];
     16 int dfn[maxn], low[maxn], vis[maxn], belong[maxn], deep, color;
     17 int dis[maxn], d_node[maxn];//dis代表从起点到该点的点权和,d_node代表起点到该点的点权最大值 
     18 stack<int>S;
     19 queue<int>Q;
     20 
     21 struct Edge
     22 {
     23     int to, next;
     24 }edge[maxm], new_edge[maxm];
     25 
     26 void add(int a, int b)
     27 {
     28     edge[++ cnt].to = b;
     29     edge[cnt].next = head[a];
     30     head[a] = cnt;
     31 }
     32 
     33 void new_add(int a, int b)
     34 {
     35     new_edge[++ new_cnt].to = b;
     36     new_edge[new_cnt].next = new_head[a];
     37     new_head[a] = new_cnt;
     38 }
     39 
     40 void tarjan(int now)
     41 {
     42     dfn[now] = low[now] = ++ deep;
     43     vis[now] = 1;
     44     S.push(now);
     45     for(int i = head[now]; i != -1; i = edge[i].next)
     46     {
     47         int to = edge[i].to;
     48         if(!dfn[to])
     49         {
     50             tarjan(to);
     51             low[now] = min(low[now], low[to]);
     52         }
     53         else if(vis[to])
     54             low[now] = min(low[now], dfn[to]);
     55     }
     56     if(low[now] == dfn[now])
     57     {
     58         color ++;
     59         while(1)
     60         {
     61             int temp = S.top();
     62             S.pop();
     63             vis[temp] = 0;
     64             belong[temp] = color;
     65             max_node[color] = max(max_node[color], arr[temp]); //存每个强连通分量里亮度最大的点的值
     66             sum_color[color] += arr[temp];//存每个强连通分量里的亮度和
     67             if(temp == now)
     68                 break;
     69         }
     70     }
     71 }
     72 
     73 void topu_sort()
     74 {
     75 //    mem(dis, -inf);
     76     while(!Q.empty())
     77         Q.pop();
     78     for(int i = 1; i <= color; i ++)//topu_sort将入度为0的入队 ,并初始化d_node,每个分量的最大亮度 
     79     {
     80         dis[i] = sum_color[i];  //初始化dis, d_node 
     81         d_node[i] = max_node[i];
     82         if(!in[i])
     83             Q.push(i);
     84     }
     85     while(!Q.empty())
     86     {
     87         int temp = Q.front();
     88         Q.pop();
     89         for(int i = new_head[temp]; i != -1; i = new_edge[i].next)
     90         {
     91             int to = new_edge[i].to;
     92             in[to] --;
     93             if(!in[to])
     94                 Q.push(to);
     95             if(dis[to] <= dis[temp] + sum_color[to])//选择新入的点,那么d_node就要与新入的缩点比较了 
     96             {
     97                 dis[to] = dis[temp] + sum_color[to];
     98                 d_node[to] = max(d_node[temp], max_node[to]);
     99             }
    100             /*
    101             else if(dis[to] == dis[temp] + sum_color[to])
    102                 d_node[to] =  max(d_node[temp], max_node[to]);
    103             */
    104         }
    105     }
    106     int sum = -1;
    107     int maxx;
    108     for(int i = 1; i <= color; i ++)
    109     {
    110         if(dis[i] > sum)
    111         {
    112             sum = dis[i];
    113             maxx = d_node[i];
    114         }
    115     }
    116     printf("%d %d
    ", sum, maxx);
    117 }
    118 
    119 int main()
    120 {
    121     cnt = new_cnt = deep = color = 0;
    122     mem(head, -1), mem(new_head, -1), mem(in, 0);
    123     mem(vis, 0), mem(dfn, 0), mem(low, 0);
    124     mem(max_node, -inf), mem(sum_color, 0);
    125     scanf("%d%d", &n, &m);
    126     for(int i = 1; i <= n; i ++)
    127         scanf("%d", &arr[i]);  //存每个点的光亮值 
    128     for(int i = 1; i <= m; i ++)
    129     {
    130         int a, b;
    131         scanf("%d%d", &a, &b);
    132         add(a, b);
    133     }
    134     for(int i = 1; i <= n; i ++)
    135         if(!dfn[i])
    136             tarjan(i);
    137     for(int i = 1; i <= n; i ++)
    138     {
    139         for(int j = head[i]; j != -1; j = edge[j].next)
    140         {
    141             int to = edge[j].to;
    142             int x = belong[i], y = belong[to]; //将分量连边 缩点  注意是分量 belong 
    143             if(x != y)
    144             {
    145                 new_add(x, y);
    146                 in[y] ++;
    147             }
    148         }
    149     }
    150     topu_sort();
    151     return 0;
    152 }
    View Code
  • 相关阅读:
    SpringBoot 系列教程 web 篇之自定义请求匹配条件 RequestCondition
    SpringBoot 系列教程 JPA 错误姿势之环境配置问题
    react中constructor()和super()的具体含义以及如何使用
    原生js之canvas时钟组件
    js求和运算在可变参数的情况下ES3、ES5和ES6的写法区别
    好用的jquery.animateNumber.js数字动画插件
    sublime text3中设置Emmet输入标签自动闭合
    原生js移动端列表无缝间歇向上滚动
    原生js实现preAll和nextAll方法
    基于SwiperJs的H5/移动端下拉刷新上拉加载更多
  • 原文地址:https://www.cnblogs.com/yuanweidao/p/10859790.html
Copyright © 2011-2022 走看看