zoukankan      html  css  js  c++  java
  • 洛谷 P3387 【模板】缩点 DAGdp学习记

    我们以洛谷P3387 【模板】缩点 来学习DAGdp

    1.这道题的流程

    //伪代码
      for i->n if(i未被遍历) tarjan(i)
      缩点()
      DAGdp()
      完成 

    首先tarjan这部分应该没问题,如果想看详细的可以看我的tarjan学习记

    接下来tarjan完毕,每个点属于的强连通分量也得到了,因此缩点可以进行了

    这里这部分比较麻烦,下面上的代码讲的比较清楚,注释也给了。

    所以现在讲讲DAGdp

    我刚开始看到DAPdp……什么鬼啊?(UPD:DAG为有向无环图),然后百度,啥都没有,于是自己用类似用类似拓扑排序的方法做,发现DAGdp就是在拓扑上面弄得,那么,这就好办了

    void dagdp()
    {
        int i,j;
        queue <int> q;   
        for(i=1;i<=cnt;i++)
        {
            if(!ind[i])  //找到入度为0的点,这个点一定不会被刷新,因此满足dp无后效性 
            {
            q.push(i);
            f[i]=money[i];    
            } 
        }
        while(!q.empty())
        {
            int t=q.front();
            int i,j,k;
            q.pop();
            for(i=head[t];i;i=e[i].next)
            {
            j=e[i].to;
            ind[j]--;  //这个点的入度减一 
            k=money[j];
            f[j]=max(f[t]+k,f[j]);   
            if(!ind[j])  //如果这个点入度为0,那么这个点一定被处理完了 
            q.push(j);  //那么又可以从这个点开始做 
            }
        }
    }

    因此,这道题的程序就长这个样子

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<stack>
    
    using namespace std;
    
    int size,n,m,dt,cnt;
    int head[10020],cost[10020],vis[10020],bd[10020],ins[10020],dfn[10020],low[10020],money[10010];
    stack <int> s;
    int ind[10020],chd[10020],f[10020],ans=-19000017,bl;  
    struct edge{
        int next,to,dis;
    }e[1000860],looker[1000860]; //looker是存的边的备份 
    
    void addedge(int next,int to,int dis)
    {
        e[++size].dis=dis;
        e[size].to=to;
        e[size].next=head[next];
        head[next]=size;
    }
    
    int pd(int a,int b)  //判断边是否重复 
    {
        for(int i=head[a];i;i=e[i].next)
        {
            int j=e[i].to;
            if(j==b) return 1;
        }
        return 0;
    }
    
    void tarjan(int t)  //tarjan操作 
    {
        dfn[t]=low[t]=++bl;
        s.push(t);
        ins[t]=1;
        int i,j;
        for(i=head[t];i;i=e[i].next)
        {
            j=e[i].to;
            if(!dfn[j])
            {
                tarjan(j);
                low[t]=min(low[t],low[j]);
            }
            else if(ins[j]) low[t]=min(dfn[j],low[t]);
        }
        j=0;
        if(dfn[t]==low[t])
        {
            cnt++;
            while(t!=j)
            {
                j=s.top();
                s.pop();
                ins[j]=0;
                bd[j]=cnt;
            }
         } 
    }
    
    void dagdp()
    {
        int i,j;
        queue <int> q;   
        for(i=1;i<=cnt;i++)
        {
            if(!ind[i])  //找到入度为0的点,这个点一定不会被刷新,因此满足dp无后效性 
            {
            q.push(i);
            f[i]=money[i];    
            } 
        }
        while(!q.empty())
        {
            int t=q.front();
            int i,j,k;
            q.pop();
            for(i=head[t];i;i=e[i].next)
            {
            j=e[i].to;
            ind[j]--;  //这个点的入度减一 
            k=money[j];
            f[j]=max(f[t]+k,f[j]);   
            if(!ind[j])  //如果这个点入度为0,那么这个点一定被处理完了 
            q.push(j);  //那么又可以从这个点开始做 
            }
        }
    }
    
    int main()
    {
        int i,j;
        scanf("%d %d",&n,&m);
        for(i=1;i<=n;i++)
        scanf("%d",&cost[i]);
        for(i=1;i<=m;i++)
        {
            int t1,t2;
            scanf("%d %d",&t1,&t2);
            addedge(t1,t2,0);
            looker[i].next=t1;
            looker[i].to=t2;
        }
        for(i=1;i<=n;i++) if(!dfn[i])tarjan(i);
        memset(head,0,sizeof(head));
        size=0;
        for(i=1;i<=n;i++)
        {
        money[bd[i]]+=cost[i];
        }
        for(i=1;i<=m;i++)
        {
            if(bd[looker[i].next]==bd[looker[i].to]) continue;  //我 到 我自己 ? 
            if(!pd(bd[looker[i].next],bd[looker[i].to])) 
            {
            addedge(bd[looker[i].next],bd[looker[i].to],0);
            ind[bd[looker[i].to]]++; //统计入度与出度 
            chd[bd[looker[i].next]]++;
            }    
        }    
        dagdp();
        for(i=1;i<=cnt;i++) ans=max(ans,f[i]);  //比较每个点与当前最大值
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    [ERROR] Terminal initialization failed; falling back to unsupported
    设计模式原则
    设计模式:概述
    INFO Dispatcher:42
    Exception occurred during processing request: id to load is required for loading
    Java编程基础篇第六章
    Spring (一)(未完~~~
    Spring MVC处理过程理解(一)
    Spring MVC源码解析(二)
    MyBatis拦截器(一)
  • 原文地址:https://www.cnblogs.com/zsx6/p/11080823.html
Copyright © 2011-2022 走看看