• P3387 【模板】缩点


      在我们求最大路径的时候,我们应该不希望有环出现,否则的话我们可能走着走着就走回自己了么让我们需要用到我走到的点的值去更新之前的点的值,那么有环的情况下,我就要用自己的值来更新自己(其实是可以的,默认是0嘛)。但是嘛,这道题让我们可以重复经过一个点或者一条边,那么我们就什么也不用考虑了,在一个强连通分量中的点一定能互相到达,结果一定更优。(感觉自己是昧着良心说的,因为这道题不够严谨的是没强调点权是非负数,若存在负数的话,每一次都缩点不一定会有最优解)

      既然这样,我们就姑且不在意这件事,毕竟我们现在学的是方法,暂且不计较。

      那么,所有的强连通分量里面的点都可以互相到达,那么我们可以理解为,只要到了其中一个,就相当于可以到任何的其他一个,那为什么要每一次都重新跑一遍呢?这些点既然都可以互相到达,为什么不揉成一个点呢?

      所以我们只要在求出所有的强连通分量之后,按照不同的颜色,重新建图即可,最后再跑一遍记忆化就可以啦~

      代码如下:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    #define maxn 2*100005
    int head[maxn],w[maxn],st[maxn],co[maxn],dfn[maxn],low[maxn];
    int am[maxn],an[maxn],sum[maxn],f[maxn],to[maxn],nxt[maxn];
    int n,m,num,top,col,ans,cnt;
    void add(int a,int b)
    {
        to[++cnt]=b;
        nxt[cnt]=head[a];
        head[a]=cnt;
    }
    void Tarjan(int u)
    {
        dfn[u]=low[u]=++num;
        st[++top]=u;
        for(int i=head[u]; i; i=nxt[i])
        {
            int v=to[i];
            if(!dfn[v])
            {
                Tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!co[v])
                low[u]=min(low[u],low[v]);
        }
        if(low[u]==dfn[u])
        {
            co[u]=++col;
            sum[col]+=w[u];
            while(st[top]!=u)
            {
                sum[col]+=w[st[top]];
                co[st[top--]]=col;
            }
            top--;
        }
    }
    void dfs(int u)
    {
        if(f[u]) return;
        f[u]=sum[u];
        int now_max=0;
        for(int i=head[u]; i; i=nxt[i])
        {
            int v=to[i];
            dfs(v);
            now_max=max(now_max,f[v]);
        }
        f[u]+=now_max;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            scanf("%d",&w[i]);
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&am[i],&an[i]);
            add(am[i],an[i]);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                Tarjan(i);
        memset(head,0,sizeof(head));
        memset(nxt,0,sizeof(nxt));
        memset(to,0,sizeof(to));
        for(int i=1; i<=m; i++)
            if(co[am[i]]!=co[an[i]])
                add(co[am[i]],co[an[i]]);
        for(int i=1; i<=col; i++)
        {
            if(!f[i]) dfs(i);
            ans=max(ans,f[i]);
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    思维导图
    第九周学习
    java连接数据库执行SQL并把查询到的数据保存到磁盘
    火狐浏览器安装firebug和firepath插件方法(离线)
    selenium自动化测试资源整理(含所有版本chrome、chromedriver、firefox下载链接)
    Jenkins调度Selenium脚本不能打开浏览器解决办法
    selenium如何操作HTML5的画布canvas上的元素
    Java中如何使用非强制类型转换把字符串转换成int类型
    自动化测试如何使用driver.findElements去操作页面元素
    Jmeter响应数据中文乱码
  • 原文地址:https://www.cnblogs.com/popo-black-cat/p/10285561.html
Copyright © 2020-2023  润新知