• APIO2009 抢掠计划 Tarjan DAG-DP


    APIO2009 抢掠计划 Tarjan spfa/DAG-DP

    题面

    一道(Tarjan)缩点水题。因为可以反复经过节点,所以把一个联通快中的所有路口看做一个整体,缩点后直接跑(spfa)或者dp就好了。

    在DAG上跑dp,复杂度(O(n)),而(spfa)(O(kn)),所以还是优先选择dp(当然后面有(spfa​)的代码)

    拓扑时搞DP,(f[i]​)表示在DAG上(i​)节点时,当前最大钱数,转移(f[v]=max(f[v], f[u]+w[v])​)

    #include <cstdio>
    #include <queue>
    #define MAXN 500005
    #define MIN(A,B) ((A)<(B)?(A):(B))
    #define MAX(A,B) ((A)>(B)?(A):(B))
    using namespace std;
    int n,m,sta,p;
    bool hav[MAXN],col_hav[MAXN];
    int head[MAXN],nxt[MAXN],vv[MAXN],tot;
    inline void add_edge(int u, int v){
        vv[++tot]=v;
        nxt[tot]=head[u];
        head[u]=tot;
    }
    int s[MAXN],top;
    bool ins[MAXN];
    int col[MAXN],col_cnt;
    int val[MAXN],col_val[MAXN];
    int low[MAXN],dfn[MAXN],cnt;
    void tarjan(int u){
        dfn[u]=++cnt;
        low[u]=cnt;
        s[++top]=u;
        ins[u]=1;
        for(register int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(dfn[v]==0){
                tarjan(v);
                low[u]=MIN(low[u], low[v]);
            }else if(ins[v]){
                low[u]=MIN(low[u], dfn[v]);
            }
        }
        if(dfn[u]==low[u]){
            col[u]=++col_cnt;
            ins[u]=0;
            col_val[col_cnt]=val[u];
            while(s[top]!=u){
                col[s[top]]=col_cnt;
                ins[s[top]]=0;
                col_val[col_cnt]+=val[s[top]];
                top--;
            }
            top--;
        }
    }
    int head2[MAXN],nxt2[MAXN],vv2[MAXN],tot2;
    inline void add_edge2(int u, int v){
        vv2[++tot2]=v;
        nxt2[tot2]=head2[u];
        head2[u]=tot2;
    }
    int rdu[MAXN];
    inline void build(){
        for(register int u=1;u<=n;++u)
        if(dfn[u]!=0){
            for(register int i=head[u];i;i=nxt[i]){
                int v=vv[i];
                if(col[u]==col[v]) continue;
                rdu[col[v]]++;
                add_edge2(col[u], col[v]);
            }
        }
    }
    queue <int> q;
    int f[MAXN],ans=0;
    void dp(){
        q.push(col[sta]);f[col[sta]]=col_val[col[sta]];
        while(!q.empty()){
            int u=q.front();q.pop();
            for(register int i=head2[u];i;i=nxt2[i]){
                int v=vv2[i];
                f[v]=MAX(f[v], f[u]+col_val[v]);
                if((--rdu[v])==0) q.push(v);
            }
        }
        for(register int i=1;i<=col_cnt;++i)
            if(col_hav[i]) ans=MAX(f[i], ans);
    }
    int main()
    {
        scanf("%d %d", &n, &m);
        while(m--){
            int a,b;scanf("%d %d", &a, &b);
            add_edge(a,b);
        }
        for(register int i=1;i<=n;++i) scanf("%d", &val[i]);
        scanf("%d %d", &sta, &p);
        while(p--){
            int x;scanf("%d", &x);
            hav[x]=1;
        }
        tarjan(sta);
        for(register int i=1;i<=n;++i)
            if(hav[i]) col_hav[col[i]]=1;
        build();
        dp();
        printf("%d", ans);
        return 0;
    }
    

    但是比赛时,拓扑dp写炸了,于是换成了(spfa),下面是(spfa)的写法:

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define MAXN 500005
    #define MAXM 500005
    #define MIN(A,B) ((A)<(B)?(A):(B))
    #define MAX(A,B) ((A)>(B)?(A):(B))
    using namespace std;
    int n,m,val[MAXM],sta,p;
    int head[MAXM],nxt[MAXM],vv[MAXM],tot;
    inline void add_edge(int u, int v){
        vv[++tot]=v;
        nxt[tot]=head[u];
        head[u]=tot;
    }
    int low[MAXN],dfn[MAXN],cnt;
    int s[MAXN],top;
    int col[MAXN],col_cnt;
    long long col_val[MAXN];
    bool ins[MAXN];
    bool col_can[MAXN];
    bool hav[MAXN];
    bool col_hav[MAXN];
    void tarjan(int u){
        ins[u]=1;
        dfn[u]=low[u]=++cnt;
        s[++top]=u;
        for(register int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(dfn[v]==0){
                tarjan(v);
                low[u]=MIN(low[u], low[v]);
            }else if(ins[v]){
                low[u]=MIN(low[u], dfn[v]);
            }
        }
        if(low[u]==dfn[u]){
            ins[u]=0;
            col[u]=++col_cnt;
            col_val[col_cnt]=val[u];
            if(hav[u]) col_hav[col_cnt]=1;
            while(s[top]!=u){
                col[s[top]]=col_cnt;
                ins[s[top]]=0;
                col_val[col_cnt]+=val[s[top]];
                if(hav[s[top]]) col_hav[col_cnt]=1;
                top--;
            }
            top--;
        }
    }
    int du[MAXN];
    int head2[MAXN],nxt2[MAXM],vv2[MAXM],tot2;
    inline void add_edge2(int u, int v){
        vv2[++tot2]=v;
        nxt2[tot2]=head2[u];
        head2[u]=tot2;
    }
    void build(){
        for(register int u=1;u<=n;++u)
        for(register int i=head[u];i;i=nxt[i]){
            int v=vv[i];
            if(col[u]==col[v]) continue;
            add_edge2(col[u], col[v]);
            du[col[v]]++;
        }
    }
    queue <int> q;
    long long f[MAXN];
    long long ans;
    bool inq[MAXN];
    void spfa(){
        f[col[sta]]=col_val[col[sta]];
        q.push(col[sta]);
        while(!q.empty()){
            int u=q.front();q.pop();
            inq[u]=0;
            for(register int i=head2[u];i;i=nxt2[i]){
                int v=vv2[i];
                if(f[v]<f[u]+col_val[v]){
                    f[v]=f[u]+col_val[v];
                    if(!inq[v]) inq[v]=1,q.push(v);
                }
            }
        }
        for(register int i=1;i<=col_cnt;++i)
            if(col_hav[i]) ans=MAX(ans, f[i]);
    }
    int main()
    {
        scanf("%d %d", &n, &m);
        while(m--){
            int a,b;scanf("%d %d", &a, &b);
            add_edge(a,b);
        }
        for(register int i=1;i<=n;++i)
            scanf("%d", &val[i]);
        scanf("%d %d", &sta, &p);
        while(p--){
            int x;scanf("%d", &x);
            hav[x]=1;
        }
        tarjan(sta);
        build();
        spfa();
        printf("%lld", ans);
        return 0;
    }
    
  • 相关阅读:
    NgModelController: $setViewValue,$render,Formatter, Parser
    #!/usr/bin/env python与#!/usr/bin/python的区别
    post发送数据 mypost input 改变事件
    post发送 ArrayBuffer
    C# 字符串到字节数组,字节数组转整型
    C# WebKitBrowser 设置内容
    C# Tuple 创建一个新二元集合
    C# 时间对比
    C# 控件调整
    C# invoke和begininvoke的用法 __委托
  • 原文地址:https://www.cnblogs.com/santiego/p/10943425.html
Copyright © 2020-2023  润新知