• 【JZOJ4771】【NOIP2016提高A组模拟9.9】爬山


    题目描述

    国家一级爬山运动员h10今天获得了一张有着密密麻麻标记的地图,在好奇心的驱使下,他又踏上了去爬山的路。
    对于爬山,h10有一个原则,那就是不走回头路,于是他把地图上的所有边都标记成了有向边。他决定从点S出发,每到达一个新的节点他就可以获得一定的成就值。同时h10又是一个很珍惜时间的运动员,他不希望这次爬山的成就值白白浪费,所以最后他一定要在一个存档点停下,保存自己的成就值。
    请你计算出在此次爬山运动中h10能够得到的最大成就值。保证h10能走到存档点。

    输入

    第一行两个整数 N,M,表示点数和边数。
    接下来 M 行,每行两个整数 u,v,表示u到v有一条有向边(没有自环)。
    第 M+2 行 N 个正整数,表示每个点的成就值。
    接下来一行两个整数 S,p,表示出发点和存档点个数。
    下面一行 p 个整数,表示存档点。

    输出

    一个正整数,表示最大成就值。

    样例输入

    5 7
    5 1
    3 1
    2 5
    3 5
    4 3
    4 2
    4 5
    7 6 3 2 2
    4 3
    1 5 2

    样例输出

    17

    数据范围

    对于 30% 的数据, N,M≤1000,并且地图为有向无环图。
    对于 100% 的数据, N,M≤500000。(数据有梯度,注意答案的大小)

    解法

    这道题模型很明显,考虑图是一个DAG(有向无环图)的时候,拓扑排序上动态规划即可。
    对于有环的情况,发现一个环的贡献是这个环上所有点的权值之和。
    所以使用强连通分量把每个环都缩成一个点。
    再使用拓扑排序上动态规划即可。
    ※手写栈需要

    代码

    #include<iostream>
    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    #include<algorithm>
    #define ll long long
    #define ln(x,y) ll(log(x)/log(y))
    #define sqr(x) ((x)*(x))
    using namespace std;
    const char* fin="aP2.in";
    const char* fout="aP2.out";
    const ll inf=0x7fffffff;
    const ll maxn=500007,maxm=maxn*2;
    ll n,m,i,j,k,st,En,tot,num;
    ll a[maxn],fi[maxn],ne[maxm],la[maxm];
    ll stack[maxn],dfn[maxn],low[maxn],fa[maxn];
    ll ru[maxn];
    ll b[maxn];
    ll f[maxn],ans;
    ll cz[maxn];
    bool bz[maxn],en[maxn];
    ll read(){
        ll x=0;
        char ch=getchar();
        while (ch<'0' || ch>'9') ch=getchar();
        while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    void add_line(ll a,ll b){
        tot++;
        ne[tot]=fi[a];
        la[tot]=b;
        fi[a]=tot;
    }
    struct handstack{
        ll i,j,k,v;
    }hs[maxn];
    int hst=0;
    void handdfs(ll v){
        hs[++hst].v=v;
        hs[hst].i=0;
        while (hst){
            if (hs[hst].i){
                if (hs[hst].k){
                    if (!dfn[la[hs[hst].k]]) {
                        hs[hst+1].v=la[hs[hst].k];
                        hs[hst+1].i=0;
                        hst++;
                        continue;
                    }else if (bz[la[hs[hst].k]]) low[hs[hst].v]=min(low[la[hs[hst].k]],low[hs[hst].v]);
                    hs[hst].k=ne[hs[hst].k];
                }else{
                    if (low[hs[hst].v]==dfn[hs[hst].v]){
                        while (stack[0]>hs[hst].j) {
                            for (hs[hst].k=fi[stack[stack[0]]];hs[hst].k;hs[hst].k=ne[hs[hst].k]) add_line(hs[hst].v,la[hs[hst].k]);
                            fa[stack[stack[0]]]=hs[hst].v;
                            a[fa[stack[stack[0]]]]+=a[stack[stack[0]]];
                            bz[stack[stack[0]--]]=false;
                        }
                        fa[stack[stack[0]]]=hs[hst].v;
                        bz[stack[stack[0]--]]=false;
                    }
                    hst--;
                }
            }else{
                hs[hst].i=1;
                dfn[hs[hst].v]=low[hs[hst].v]=++num;
                bz[stack[hs[hst].j=++stack[0]]=hs[hst].v]=true;
                hs[hst].k=fi[hs[hst].v];
            }
        }
    }
    void dfs(ll v){
        ll i,j,k;
        dfn[v]=low[v]=++num;
        bz[stack[j=++stack[0]]=v]=true;
        for (k=fi[v];k;k=ne[k])
            if (!dfn[la[k]]) {
                dfs(la[k]);
                low[v]=min(low[la[k]],low[v]);
            }else if (bz[la[k]]) low[v]=min(dfn[la[k]],low[v]);
        if (low[v]==dfn[v]){
            while (stack[0]>j) {
                for (k=fi[stack[stack[0]]];k;k=ne[k]) add_line(v,la[k]);
                fa[stack[stack[0]]]=v;
                a[fa[stack[stack[0]]]]+=a[stack[stack[0]]];
                bz[stack[stack[0]--]]=false;
            }
            fa[stack[stack[0]]]=v;
            bz[stack[stack[0]--]]=false;
        }
    }
    void topsort(){
        ll i,j,k,head=0,tail=0;
        for (i=1;i<=n;i++){
            if (fa[i] && i==fa[i]) for (k=fi[i];k;k=ne[k]){
                if (/*cz[fa[la[k]]]<i && */fa[la[k]]!=i) ru[fa[la[k]]]++/*,cz[fa[la[k]]]=i*/;
            }
        }
        for (i=1;i<=n;i++) if (!ru[i] && fa[i]==i) {
            b[++tail]=i;
            f[i]=a[i];
            break;
        }
        while (head++<tail){
            if (en[b[head]]) ans=max(ans,f[b[head]]);
            for (k=fi[b[head]];k;k=ne[k]) if (fa[la[k]]!=b[head]){
                i=fa[la[k]];
                f[i]=max(f[i],f[b[head]]+a[i]);
                if (--ru[i]==0) b[++tail]=i;
            }
        }
    }
    int main(){
        n=read();m=read();
        for (i=1;i<=m;i++){
            j=read();k=read();
            add_line(j,k);
        }
        for (i=1;i<=n;i++) a[i]=read();
        st=read();En=read();
        handdfs(st);
        for (i=1;i<=En;i++) j=read(),en[fa[j]]=true;
        topsort();
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    web服务器12 中间件函数
    web11 路由
    web服务器15 jsonp格式接口
    web服务器14 cors跨域资源共享 报错及解决方案
    小程序弹窗(模态框)遮罩层 弹窗右上角按钮关闭
    数据库1 mysq数据库的安装全套
    MySQL数据库3 的 where语句 and 和 or运算符
    MySQL数据库2 增删改查
    MySQL分组排序取每组第一条
    IDEA频繁闪退解决
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714900.html
Copyright © 2020-2023  润新知