BZOJ1179 [Apio2009]Atm Tarjan 强连通缩点 动态规划

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1179


题意概括

  有一个有向图,每一个节点有一个权值,其中有一些结束点。

  现在,你要从S出发,到达任意一个结束点,使得经过的节点的权值和最大(可以重复经过某一个节点,但是权值只记入一次)。


 

题解

  小码农题。

  如果有强连通分量,那么之间的点是可以全部拿到的,傻子才不拿。

  所以先Tarjan强连通缩个点。

  然后就是一个DAG(有向无环图)了。

  那么就是一个记忆化dfs的问题了。

  于是就简单了。

  but,尴尬的我犯了低级错误,又wa了一次……

  


 

代码

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=500000+5;
const int Inf=2100000000;
struct Gragh{
    int cnt,x[N],y[N],nxt[N],fst[N];
    void set(){
        cnt=0;
        memset(fst,0,sizeof fst);
    }
    void add(int a,int b){
        x[++cnt]=a,y[cnt]=b;
        nxt[cnt]=fst[a],fst[a]=cnt;
    }
}g,g2;
int n,m,time,top,tot;
int dfn[N],low[N],bh[N],st[N],w[N],v[N],dp[N],S,P;
bool inst[N],vis[N],isp[N],fip[N];
void Tarjan_Prepare(){
    time=top=tot=0;
    memset(bh,0,sizeof bh);
    memset(st,0,sizeof st);
    memset(dfn,0,sizeof dfn);
    memset(low,0,sizeof low);
    memset(vis,0,sizeof vis);
    memset(inst,0,sizeof inst);
}
void Tarjan(int x){
    dfn[x]=low[x]=++time;
    inst[x]=vis[x]=1;
    st[++top]=x;
    for (int i=g.fst[x];i;i=g.nxt[i])
        if (!vis[g.y[i]]){
            Tarjan(g.y[i]);
            low[x]=min(low[x],low[g.y[i]]);
        }
        else if (inst[g.y[i]])
            low[x]=min(low[x],low[g.y[i]]);
    if (dfn[x]==low[x]){
        tot++;
        bh[st[top]]=tot;
        inst[st[top]]=0;
        while (st[top--]!=x){
            bh[st[top]]=tot;
            inst[st[top]]=0;
        }
    }
}
int dfs(int x){
    if (dp[x]!=-Inf)
        return dp[x];
    dp[x]=fip[x]?v[x]:-Inf;
    for (int i=g2.fst[x];i;i=g2.nxt[i])
        dp[x]=max(dp[x],dfs(g2.y[i])+v[x]);
    return dp[x];
}
int main(){
    g.set();
    scanf("%d%d",&n,&m);
    for (int i=1,a,b;i<=m;i++){
        scanf("%d%d",&a,&b);
        g.add(a,b);
    }
    for (int i=1;i<=n;i++)
        scanf("%d",&w[i]);
    scanf("%d%d",&S,&P);
    memset(isp,0,sizeof isp);
    memset(fip,0,sizeof fip);
    memset(v,0,sizeof v);
    for (int i=1,pos;i<=P;i++){
        scanf("%d",&pos);
        isp[pos]=1;
    }
    Tarjan_Prepare();
    for (int i=1;i<=n;i++)
        if (!vis[i])
            Tarjan(i);
    g2.set();
    for (int i=1;i<=n;i++)
        v[bh[i]]+=w[i],fip[bh[i]]|=isp[i];
    for (int i=1;i<=g.cnt;i++)
        if (bh[g.x[i]]!=bh[g.y[i]])
            g2.add(bh[g.x[i]],bh[g.y[i]]);
    for (int i=1;i<=tot;i++)
        dp[i]=-Inf;
    printf("%d",dfs(bh[S]));
    return 0;
}

 

posted @ 2017-08-17 16:18  zzd233  阅读(262)  评论(0编辑  收藏  举报