寒假学习笔记【匠心制作,图文并茂】——1.20拓扑、强连通分量、缩点

06-01 1392阅读

文章目录

  • 前言
  • 拓扑排序
    • 拓扑排序是怎么运作的
    • 拓扑排序的好处
    • 强连通分量
      • 强连通是什么
      • 强连通分量是什么
      • 如何求 SCC
      • 缩点

        前言

        更新的稍微有点晚……

        因为强连通分量这一块难学且知识点多,学习时间久了亿点,所以直到现在才更新。

        拓扑排序

        OI-Wiki 是这么定义拓扑排序的:

        拓扑排序(Topological sorting)要解决的问题是如何给一个有向无环图的所有节点排序。

        这个感觉不是很像定义,更像是它在干什么,我们来重新定义一下拓扑排序:

        拓扑排序是一种将一个有向无环图(Directed Acyclic Graph,简称 DAG)按照一定顺序对所有节点进行排序的算法。

        注意:只能在有向无环图上跑拓扑。

        拓扑排序是怎么运作的

        接下来我就要开始操作了,注意步骤:

        1. 取出图中入度为 0 0 0 的点,加入队列。
        2. 取出队头,将与队头相连的点的入度全减 1 1 1。
        3. 将图上入度为 0 0 0 的点加入队列。
        4. 重复执行 2 2 2、 3 3 3 操作。
        5. 想你的诗和远方吧……

        没看明白的观众就请看下面的模拟,看明白了的,也还是看一下案例吧。

        我们先随机生成一个 DAG:

        寒假学习笔记【匠心制作,图文并茂】——1.20拓扑、强连通分量、缩点

        首先按照第一步:取出图中入度为 0 0 0 的点并放入队列(如果你连入度是啥都不知道,那你就不应该出现在这)。图中入度为 0 0 0 的点不就是 1 1 1 吗?此时队列中有一个 1 1 1。

        寒假学习笔记【匠心制作,图文并茂】——1.20拓扑、强连通分量、缩点

        然后进行第二步:取出队头,将与队头相连的点的入度全减 1 1 1。队头就是 1 1 1,那么我们取出 1 1 1 并将所有与队头相连的点入度减 1 1 1,整张图就相当于变成了这样:

        寒假学习笔记【匠心制作,图文并茂】——1.20拓扑、强连通分量、缩点

        队列此时为空。

        然后进行第三步:将图上入度为 0 0 0 的点加入队列。图上入度为 0 0 0 的点有 2 2 2 和 3 3 3,所以把它们加入队列,于是队列变成了这样:

        寒假学习笔记【匠心制作,图文并茂】——1.20拓扑、强连通分量、缩点

        然后就是重复执行以上操作……

        最后,我们得到的拓扑序就是这三种中的一种:1 2 3 6 4 5、1 3 2 4 6 5、1 3 2 6 4 5。

        不难看出,一张图的拓扑序可以有很多个。所以这类题一般都是 SPJ(Special Judge)。

        以 洛谷 B3644 为例,代码如下:

        #include
        #define int long long
        using namespace std;
        int n,rd[106];
        vectorv[106];
        queueq;
        signed main()
        {
        	cin>>n;
        	for(int x,i=1;i
        		while(cin>x&&x)
        		{
        			v[i].emplace_back(x);
        			rd[x]++;
        		}
        	}
        	for(int i=1;i
        		if(rd[i]==0)
        		{
        			q.emplace(i);
        		}
        	}
        	while(!q.empty())//第二、三步
        	{
        		int x=q.front();
        		q.pop();
        		cout
        			rd[i]--;
        			if(rd[i]==0)
        			{
        				q.emplace(i);
        			}
        		}
        	}
        	return 0;
        }
        
            dfn[x]=low[x]=++ti;//记录编号
            st.emplace(x);
            ins[x]=1;
            for(auto i:v[x])
            {
                if(!dfn[i])
                {
                    tarjan(i);
                    low[x]=min(low[x],low[i]);//更新
                }
                else if(ins[i])
                {
                    low[x]=min(low[x],dfn[i]);
                }
            }
            if(low[x]==dfn[x])//找到 SCC
            {
                cnt++;
                while(1)
                {
                    int u=st.top();
                    st.pop();
                    ins[u]=0;
                    belong[u]=cnt;//记录下来每个点属于哪个 SCC(主要是为了缩点)
                    b[u]=cnt;
                    vv[cnt].emplace_back(u);//记录下来有哪些点
                    if(u==x)
                    {
                        break;
                    }
                }
            }
        }
        signed main()
        {
            cinnm;
            for(int x,y,i=1;i
                cinx>>y;
                v[x].emplace_back(y);
            }
            for(int i=1;i
                if(!dfn[i])
                {
                    tarjan(i);
                }
            }
            for(int i=1;i
                sort(vv[i].begin(),vv[i].end());
            }
            cout
                if(!vis[b[i]])
                {
                    for(auto j:vv[b[i]])
                    {
                        cout
            dfn[x]=low[x]=++ti;
            st.emplace(x);
            ins[x]=1;
            for(auto i:v[x])
            {
                if(!dfn[i])
                {
                    tarjan(i);
                    low[x]=min(low[x],low[i]);
                }
                else if(ins[i])
                {
                    low[x]=min(low[x],dfn[i]);
                }
            }
            if(low[x]==dfn[x])
            {
                ++cnt;
                while(1)
                {
                    int u=st.top();
                    st.pop();
                    ins[u]=0;
                    belong[u]=cnt;
                    b[cnt]+=a[u];
                    if(u==x)
                    {
                        break;
                    }
                }
            }
        }
        int topsort()//拓扑排序
        {
            for(int i=1;i
                if(!rd[i])
                {
                    q.emplace(i);
                    dis[i]=b[i];
                }
            }
            while(!q.empty())
            {
                int x=q.front();
                q.pop();
                for(auto i:vv[x])
                {
                    dis[i]=max(dis[i],dis[x]+b[i]);
                    rd[i]--;
                    if(!rd[i])
                    {
                        q.emplace(i);
                    }
                }
            }
            int ans=0;
            for(int i=1;i
                ans=max(ans,dis[i]);
            }
            return ans;
        }
        signed main()
        {
            cinnm;
            for(int i=1;i
                cina[i];
            }
            for(int i=1,x,y;i
                cinxy;
                v[x].emplace_back(y);
            }
            for(int i=1;i
                if(!dfn[i])
                {
                    tarjan(i);
                }
            }
            for(int i=1;i
                for(auto j:v[i])
                {
                    if(belong[i]!=belong[j]&&!mp[make_pair(belong[i],belong[j])])
                    //这里有时需要判重,有时又不需要,主要是看重边会不会有影响
                    //如果只是单纯跑拓扑是没有什么影响的,但如果要做与边相关的运算就有影响了
                    {
                        vv[belong[i]].emplace_back(belong[j]);
                        rd[belong[j]]++;
                        mp[make_pair(belong[i],belong[j])]=1;
                    }
                }
            }
            cout
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码