Title

【图论】拓扑排序

拓扑排序

引入

某街区犯罪率骤然上升,经过探员007的暗地调查,该地存在黑帮组织,调查局打算采取找到黑帮老大并将其监禁的方法,来弱化黑帮势力,但黑帮内部一旦失去老大后,二把手会自动向上补位,现在作为调查局一员的你,请根据一份黑帮内部从属关系的资料,要求把一份监禁顺序名单递交给上级。

理解

一旦黑帮老大被监禁后,二把手的直属上级关系数就要减一(入度减一),直到二把手没有直接上级时(入度为0),二把手晋升为新的黑帮老大。

模板题

AcWing 1191. 家谱树

拓扑排序的应用

判断是否存在环

  • 由于环上任意一点的入度都为0,所以在初始化和运算过程中都不存在加入的可能。所以当被操作的点数小于总点数时,图中存在环(而通常在问题的复原中,环代表这矛盾的存在,即题目无解)

AcWing 1192. 奖金(有差分约束的味道,要max一下)

  • 关于拓扑的起点可以灵活一点,可以从更改指向关系(相当于把a吃b变成了b被a吃),如把add(a,b)改成add(b,a),vec[a].push_back(b)改成vec[b].push(a).同时记得把indegree[a]=b改成indegree[b]=a;

  • #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e4+10;
    int n,m;
    int money[N];
    
    int h[N],e[2*N],ne[2*N],idx=0;
    void add(int a,int b)
    {
    	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    }
    
    int in_d[N];
    bool topsort()
    {
    	queue<int > q;
    	for(int i=1;i<=n;i++)
    	{
    		if(in_d[i]==0)
    		{
    			money[i] = 100;		   
    			q.push(i);
    		}
    	}
    	
    	int cnt=0;
    	while(q.size())
    	{
    		int t = q.front();
    		q.pop();
    		cnt++;
    		for(int i=h[t];~i;i=ne[i])
    		{
    			int j = e[i];
    			in_d[j]--;
    			if(in_d[j]==0)
    			{
    				q.push(j);
    				money[j] = max(money[j ] , money[t] + 1);
    			//	cout<<j<<" "<<money[j]<<endl;
    			}
    		}
    	}
    	return cnt==n;
    }
    int main()
    {
    	memset(h,-1,sizeof(h));
    	
    	cin>>n>>m;
    	for(int i=0;i<m;i++)
    	{
    		int a,b;
    		cin>>a>>b;
    		add(b,a);
    		in_d[a]++;
    	}
    	if(!topsort())
    	{
    		cout<<"Poor Xed";
    	}
    	else
    	{
    	   int total=0;
    	   for(int i=1;i<=n;i++)
        	{
    	    	total=total+money[i];
    	    }
    	    cout<<total;
    	}
    	return 0;
    }
    

可达性统计(在DAG图中,统计一个点可以到达的后续结点的个数)

Acwing 164 . 可达性统计
前置知识:bitset

给定一张 N个点 M 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。

#include<bits/stdc++.h>
using namespace std;
const int N = 3e4+10;
bitset <N+1> nums[N+1];
vector <int > ans;
vector <int > order;
int n,m;

int h[N],ne[N*2],e[N*2],idx=0;
void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}


int in_d[N];
void topsort()
{
	queue<int > q;
	for(int i=1;i<=n;i++)
	{
		if(in_d[i]==0)q.push(i);
	}
	
	while(q.size())
	{
		int t = q.front();
		q.pop();
		order.push_back(t);
		for(int i = h[t];~i;i=ne[i])
		{
			int j = e[i];
			if(--in_d[j]==0)
			   q.push(j);
		}
	}
}

void process()
{
    for(int i=n-1;i>=0;i--)
	{
		int st = order[i];
	    for(int j = h[st];~j;j=ne[j])
	    {
	    	int k=e[j];
	    	nums[st] = nums[st] | nums[k];
		}
	}	
}

void print()
{
	for(int i=1;i<=n;i++)
       cout<<nums[i].count()<<endl;
}

int main()
{
	memset(h,-1,sizeof(h));
	memset(in_d,0,sizeof(in_d));
	
	cin>>n>>m;

	for(int i=1;i<=n;i++)
	{
		nums[i].reset();
		nums[i].set(i);
	}
	   
	
	for(int i=0;i<m;i++)
	{
		int aa,bb;
		cin>>aa>>bb;
		add(aa,bb);
		in_d[bb]++;
	} 
	
	topsort();
	process();
	print();
	
	return 0;
}


其他

  • 将函数返回类型改为bool
  • DAG(Directed Acyclic Graph)
  • bitset
posted @ 2021-07-19 17:30  BeautifulWater  阅读(55)  评论(0编辑  收藏  举报