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
  • 相关阅读:
    打开安装 好的Microsoft Dynamics CRM 4.0 报错误为 Caller does not have enough privilege to set CallerOriginToken to the specified value 的解决办法
    基于 Windows Server 2008 的计算机对 Microsoft Dynamics CRM 4.0 的支持
    Microsoft Dynamics CRM 4.0 如何添加自定义按钮
    Microsoft Dynamics CRM 4.0 Plugin 取值,赋值,查询
    C# 中的 enum(枚举) 类型使用例子
    vue事件的绑定
    表单验证2
    node中模块
    node模块的引入
    node中的读文件
  • 原文地址:https://www.cnblogs.com/BeautifulWater/p/15031238.html
Copyright © 2011-2022 走看看