P3387 -缩点-DAGdp

  •  P3387 【模板】缩点

  • 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。
  • 允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。
  • #include<bits/stdc++.h>
    using namespace std;
    #define maxn 12345
    int head[maxn],tme,n,m,w[maxn];
    int low[maxn],dfn[maxn],stk[maxn];
    int top,cnt,x,y,numm;
    int dp[maxn],in[maxn],fa[maxn],ans;
    bool instack[maxn];
    struct node
    {
        int v,to;
    } edge[maxn*10];
    struct edg
    {
        int x,y;
    } daa[maxn*10];
    void add(int u,int v)
    {
        edge[++cnt].to=head[u];
        edge[cnt].v=v;
        head[u]=cnt;
    }
    void tarjan(int u)
    {
        int v;
        low[u]=dfn[u]=++tme;
        stk[top++]=u;
        instack[u]=1;
        for(int i=head[u]; i!=-1; i=edge[i].to)
        {
            v=edge[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            if(instack[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            cnt++;
            do
            {
                v=stk[--top];
                fa[v]=u;
                instack[v]=0;
                if(u!=v)
                    w[u]+=w[v];
            }
            while(u!=v);
        }
    }
    void topo()
    {
        queue<int>q;
        for(int i=1; i<=n; i++)
        {
            if(fa[i]==i&&!in[i])
            {
                q.push(i);
                dp[i]=w[i];
            }
        }
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u]; i!=-1; i=edge[i].to)
            {
                int v=edge[i].v;
                dp[v]=max(dp[v],dp[u]+w[v]);
                in[v]--;
                if(in[v]==0)q.push(v);
            }
        }
        for(int i=1; i<=n; i++)
            ans=max(ans,dp[i]);
        printf("%d\n",ans);
    }
    void solve()
    {
        for(int i=1; i<=n; i++)
            if(!dfn[i])tarjan(i);
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=0; i<m; i++)
        {
            if(fa[daa[i].x]==fa[daa[i].y])continue;
            add(fa[daa[i].x],fa[daa[i].y]);
            in[fa[daa[i].y]]++;
        }
        topo();
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&w[i]);
            fa[i]=i;
        }
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            daa[i].x=x;
            daa[i].y=y;
        }
        solve();
        return 0;
    }
  •  

猜你喜欢

转载自blog.csdn.net/BePosit/article/details/84846716
今日推荐