码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P3387 【模板】缩点

时间:2020-07-26 23:07:29      阅读:56      评论:0      收藏:0      [点我收藏+]

标签:queue   记忆化   搜索   turn   alt   false   while   struct   ack   

技术图片

技术图片

思路

这个题不难,就是先Trajan缩点减小点数和边数的规模,然后在缩完点的图上跑DP即可。注意要用toposort解决DP后效性(或者是使用记忆化搜索)。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define MAXN 10010
#define MAXM 500100
int n, m, idx;
int head_b[MAXN], cnt_b;
int head_r[MAXN], cnt_r;
int dfn[MAXN], low[MAXN];
int bel[MAXN], flag[MAXN];
int in[MAXN], val[MAXN];
int f[MAXN];
struct node_basic{
    int from, nxt, to;
} edge_b[MAXM];
struct node_rebuild{
    int nxt, to;
} edge_r[MAXM];
inline int read(void){
    int f = 1, x = 0;char ch;
    do{ch = getchar();if(ch==‘-‘)f = -1;} while (ch < ‘0‘ || ch > ‘9‘);
    do{ x = x * 10 + ch - ‘0‘;ch = getchar();} while (ch >= ‘0‘ && ch <= ‘9‘);
    return f * x;
}
class Stack{
    private:
        int stk[MAXN], top;
    public:
        inline void Push(int x) { stk[++top] = x; return; }
        inline void Pop(void) { --top; return; }
        inline int Top(void) { return stk[top]; }
} Stk;
class Queue{
    private:
        int q[MAXN];
        int head, tail;
    public:
        inline void Push(int x) { q[++tail] = x; return; }
        inline int Front(void) { return q[head + 1]; }
        inline void Pop(void) { ++head; return; }
        inline bool Empty(void) { return head == tail ? true : false; }
} Q;
inline int _min(int x, int y) { return x < y ? x : y; }
inline int _max(int x, int y) { return x > y ? x : y; }
inline void add_edge_basic(int x,int y){
    ++cnt_b;
    edge_b[cnt_b].nxt = head_b[x];
    edge_b[cnt_b].from = x;
    edge_b[cnt_b].to = y;
    head_b[x] = cnt_b;
    return;
}
inline void add_edge_rebuild(int x,int y){
    ++cnt_r;
    edge_r[cnt_r].nxt = head_r[x];
    edge_r[cnt_r].to = y;
    head_r[x] = cnt_r;
    return;
}
void tarjan(int k){
    dfn[k] = low[k] = ++idx;
    Stk.Push(k);
    flag[k] = 1;
    for (int i = head_b[k]; i; i = edge_b[i].nxt){
        int v = edge_b[i].to;
        if(!dfn[v])
            tarjan(v), low[k] = _min(low[k], low[v]);
        else if(flag[v]) low[k] = _min(low[k], dfn[v]);
    }
    if(dfn[k]==low[k]){
        int now = -1;
        while(now!=k){
            now = Stk.Top(), Stk.Pop();
            flag[now] = 0;
            bel[now] = k;
            if(now==k) break;
            val[k] += val[now];
        }
    }
    return;
}
int toposort(void){
    for (int i = 1; i <= n; ++i){
        if(bel[i]==i&&!in[i])
            Q.Push(i), f[i] = val[i];
    }
    while(!Q.Empty()){
        int u = Q.Front(); Q.Pop();
        for (int i = head_r[u]; i; i = edge_r[i].nxt){
            int v = edge_r[i].to;
            f[v] = _max(f[v], f[u] + val[v]);
            --in[v];
            if(in[v]==0) Q.Push(v);
        }
    }
    int res = 0;
    for (int i = 1; i <= n; ++i)
        res = _max(res, f[i]);
    return res;
}
int main(){
    n = read(), m = read();
    for (int i = 1; i <= n; ++i)
        val[i] = read();
    for (int i = 1; i <= m; ++i){
        int u = read(), v = read();
        add_edge_basic(u, v);
    }
    for (int i = 1; i <= n; ++i)
        if(!dfn[i]) tarjan(i);
    for (int i = 1; i <= m; ++i){
        int u = bel[edge_b[i].from], v = bel[edge_b[i].to];
        if(u!=v) add_edge_rebuild(u, v), ++in[v];
    }
    printf("%d\n", toposort());
    return 0;
}

Luogu P3387 【模板】缩点

标签:queue   记忆化   搜索   turn   alt   false   while   struct   ack   

原文地址:https://www.cnblogs.com/ShadowFlowhyc/p/13381848.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!