• tarjan算法与拓扑排序


    算法介绍

    tarjan

    tarjan算法要求使有向图。
    Tarjan就是一个辅助作用,把有环图缩为无环图,也就是将强联通分量缩成一个点。对于每一个节点,我们用dfn[i]记录它的时间戳,用low[i]记录它的回溯值(即不经过流图搜索树上该节点父亲能返回的最小的时间戳)。dag缩点后的数组,ins是否在栈中。
    树边:dfs孩子,用其low更新本身low
    返祖边:用其dfn更新本身low,注意如果是无向图中的父边不算返祖边
    对于low=dfn的出栈并记录

    void tarjan(int x)
    {
    
    	dfn[x]=low[x]=++cnt;
    	ins[x]=1;
    	st.push(x);
    	for(int i=0;i<g[x].size();i++)
    	{
    		int q=g[x][i];
    		if(dfn[q]==0)
    		{
    			tarjan(q);
    			low[x]=min(low[x],low[q]);		
    		}
    		else if(ins[q]==1)
    		{
    			low[x]=min(low[x],dfn[q]);
    		}
    	}
    	if(dfn[x]==low[x])
    	{
    		numb++;
    		int q;
    		do
    		{
    			q=st.top();
    			st.pop();
    			ins[q]=0;
    			dag[q]=numb;
    			num[numb]++;
    			p[numb]+=a[q];
    		}
    		while(q!=x);
    	}
    
    }
    

    拓扑排序

    对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
    拓扑排序步骤
    统计入度,入度为0入栈,递推并更新入度,入度为0入栈,栈空结束

    queue<int>q;
    	int tot=0;
    	for(int i=1;i<=numb;i++)
    	{
    		if(!ind[i])
    		{
    			q.push(i);
    			dist[i]=p[i];
    		}
    	}
    	while(!q.empty())
    	{
    		int k=q.front();q.pop();
    		for(int i=0;i<g1[k].size();i++)
    		{
    			int v=g1[k][i];
    			dist[v]=max(dist[v],dist[k]+p[v]);
    			ind[v]--;
    			if(ind[v]==0)q.push(v);
    		}
    	}
    

    例题

    P3387 【模板】缩点

    代码

    const int maxn=100015;
    int numb,cnt;
    
    int dist[maxn];
    int dag[maxn],num[maxn];
    int a[maxn];
    int ind[maxn];
    stack<int>st;
    int p[maxn],dfn[maxn],ins[100015],low[100015];
    vector<int>g[maxn],g1[maxn];
    void tarjan(int x)
    {
    
    	dfn[x]=low[x]=++cnt;
    	ins[x]=1;
    	st.push(x);
    	for(int i=0;i<g[x].size();i++)
    	{
    		int q=g[x][i];
    		if(dfn[q]==0)
    		{
    			tarjan(q);
    			low[x]=min(low[x],low[q]);		
    		}
    		else if(ins[q]==1)
    		{
    			low[x]=min(low[x],dfn[q]);
    		}
    	}
    	if(dfn[x]==low[x])
    	{
    		numb++;
    		int q;
    		do
    		{
    			q=st.top();
    			st.pop();
    			ins[q]=0;
    			dag[q]=numb;
    			num[numb]++;
    			p[numb]+=a[q];
    		}
    		while(q!=x);
    	}
    
    }
    main(void)
    {
    	int n,m;
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)
    	{
    		cin>>a[i];
    	}
    	for(int i=1;i<=m;i++)
    	{
    		int u,v;
    		cin>>u>>v;
    		g[u].push_back(v);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		if(!dag[i])
    		tarjan(i);
    	}
    	for(int i=1;i<=n;i++)
    	for(int j=0;j<g[i].size();j++)
    	{
    		int u=dag[i],v=dag[g[i][j]];
    		if(u!=v)
    		{
    			g1[u].push_back(v);
    			ind[v]++;
    		}
    	}
    	queue<int>q;
    	int tot=0;
    	for(int i=1;i<=numb;i++)
    	{
    		if(!ind[i])
    		{
    			q.push(i);
    			dist[i]=p[i];
    		}
    	}
    	while(!q.empty())
    	{
    		int k=q.front();q.pop();
    		for(int i=0;i<g1[k].size();i++)
    		{
    			int v=g1[k][i];
    			dist[v]=max(dist[v],dist[k]+p[v]);
    			ind[v]--;
    			if(ind[v]==0)q.push(v);
    		}
    	}
    	int ans=0;
    	for(int i=1;i<=numb;i++)
    	ans=max(ans,dist[i]);
    	cout<<ans;
    }
    
    
    
    
  • 相关阅读:
    Application Error
    war文件
    The connection to adb is down, and a severe error has occured.
    CORS解决跨域访问问题
    实验吧_拐弯抹角(url伪静态)&Forms
    系列文章(一):探究电信诈骗的关键问题与应对策略——By Me
    企业内部安全宣贯:乌云网停摆事件的思考与评论——By Me
    安全需求-建模归类——By Me
    思考在伟大的互联网世界中,我是谁?——By Me in 2016
    去把bilibili的返回顶点锚点扒了下来
  • 原文地址:https://www.cnblogs.com/wangqianyv/p/13283049.html
Copyright © 2020-2023  润新知