• Luogu P43916 图的遍历


    我们把“u点能够到达的最大点”转化为反向图中能到达u点的所有点里的最大值,可知缩点后满足无后效性。val[i]的初值设为连通分量i中的最大点。反向存图,tarjan缩点,拓扑序dp即可。

    1. #include <iostream>  
    2. #include <cstdio>  
    3. #include <queue>  
    4. #define maxn 100100  
    5. using namespace std;   
    6. int n, m;  
    7. void read(int &x) {  
    8.     x = 0;  
    9.     char ch = getchar();  
    10.     while (!isdigit(ch))  
    11.         ch = getchar();  
    12.     while (isdigit(ch))  
    13.         x = x * 10 + (ch ^ 48),  
    14.         ch = getchar();  
    15.     return;  
    16. }  
    17. struct E {  
    18.     int to, nxt;  
    19. } edge[maxn], edge2[maxn];  
    20. int head[maxn], top, head2[maxn], top2;  
    21. inline void insert(int u, int v) {  
    22.     edge[++top] = (E) {v, head[u]};  
    23.     head[u] = top;  
    24. }  
    25. inline void insert2(int u, int v) {  
    26.     edge2[++top2] = (E) {v, head2[u]};  
    27.     head2[u] = top2;  
    28. }  
    29. int low[maxn], dfn[maxn], timer, c[maxn], cnt, sta[maxn], stp;  
    30. bool ins[maxn];  
    31. int val[maxn];  
    32. void tarjan(int u) {  
    33.     low[u] = dfn[u] = ++ timer;  
    34.     sta[++stp] = u, ins[u] = true;  
    35.     for (int i = head[u]; i; i = edge[i].nxt) {  
    36.         int v = edge[i].to;  
    37.         if (!dfn[v]) {  
    38.             tarjan(v);  
    39.             low[u] = min(low[u], low[v]);  
    40.         } else if (ins[v])  
    41.             low[u] = min(low[u], dfn[v]);  
    42.     }  
    43.     if (dfn[u] == low[u]) {  
    44.         ++cnt;  
    45.         int x;  
    46.         do {  
    47.             x = sta[stp--];  
    48.             ins[x] = false;  
    49.             c[x] = cnt;  
    50.             val[cnt] = max(val[cnt], x);  
    51.         } while (x != u);  
    52.     }  
    53. }  
    54. int ind[maxn];  
    55. void build() {  
    56.     for (int u = 1; u <= n; ++u)  
    57.         for (int i = head[u]; i; i = edge[i].nxt) {  
    58.             int v = edge[i].to;  
    59.             if (c[u] != c[v])  
    60.                 insert2(c[u], c[v]), ++ind[c[v]];  
    61.         }  
    62. }  
    63. void dp() {  
    64.     queue<int> que;  
    65.     for (int i = 1; i <= cnt; ++i)  
    66.         if (!ind[i]) que.push(i);  
    67.     while (!que.empty()) {  
    68.         int u = que.front(); que.pop();  
    69.         for (int i = head2[u]; i; i = edge2[i].nxt) {  
    70.             int v = edge2[i].to;  
    71.             val[v] = max(val[v], val[u]);  
    72.             --ind[v];  
    73.             if (!ind[v])  
    74.                 que.push(v);  
    75.         }  
    76.     }  
    77.     return;  
    78. }  
    79. int main() {  
    80.     read(n), read(m);  
    81.     int u, v;  
    82.     for (int i = 1; i <= m; ++i) {  
    83.         read(u), read(v);  
    84.         insert(v, u);  
    85.     }  
    86.     for (int i = 1; i <= n; ++i)  
    87.         if (!dfn[i])  
    88.             tarjan(i);  
    89.     build();  
    90.     dp();  
    91.     for (int i = 1; i <= n; ++i)  
    92.         printf("%d ", val[c[i]]);  
    93.     return 0;  
    94. }  

    至此luogu上真哥留下的缩点习题全部完成。晚上更新对最小树形图(朱刘算法)的理解。

  • 相关阅读:
    C/C++多文件之间的变量定义
    PKU POJ 2186 Popular Cows 强连通分量
    重载函数
    ZOJ 2763 Prison Break
    201357 训练赛总结
    hdu 4467 Graph 构造
    201356 训练赛总结
    201353 NEERC 2012, Eastern subregional contest
    2013512 CF 183 总结
    一道动态规划
  • 原文地址:https://www.cnblogs.com/TY02/p/11119893.html
Copyright © 2020-2023  润新知