zoukankan      html  css  js  c++  java
  • 【图论】拓扑排序

    拓扑排序

    引入

    某街区犯罪率骤然上升,经过探员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
  • 相关阅读:
    sge的简单的应用
    dcoker 小应用(二)
    浅谈Docker(二)
    查看Linux版本
    dcoker 小应用(一)
    linux 强制重启!
    浅谈Docker(一)
    ubuntu command
    简析hotjar录屏功能实现原理
    实现node端渲染图表的简单方案
  • 原文地址:https://www.cnblogs.com/BeautifulWater/p/15031238.html
Copyright © 2011-2022 走看看