有关Topological-sort(拓扑排序)的belabela...

Topsort的基本解释:

topsort是基于有向无环图的一种排序方法,表示事物的递推关系(从前者推到后者的顺序);

一般用队列维护;

基本思路是:根据读入的数据记录点的入度(into[999]={0}),出度(out[999]={0}),以及点与点之间的相连关系(a[1000][1000]),按入度的从小到大顺序依次把每个点进队,有相连关系的前者入队后要把后者的into--

拓扑排序的算法图解:

拓扑排序算法的基本步骤:

1. 构造一个队列Q(queue) 拓扑排序的结果队列T(topological)
2.
把所有没有依赖顶点的节点放入Q
3.
Q还有顶点的时候,执行下面步骤:
3.1
Q中取出一个顶点n(nQ中删掉),并放入T(n加入到结果集中)
3.2
n每一个邻接点m(n是起点,m是终点)
3.2.1
去掉边<n,m>;
3.2.2
如果m没有依赖顶点,则把m放入Q;
注:顶点A没有依赖顶点,是指不存在以A为终点的边。

https://github.com/wangkuiwu/datastructs_and_algorithm/blob/master/pictures/graph/topsort/01.jpg?raw=true

以上图为例,来对拓扑排序进行演示。

https://github.com/wangkuiwu/datastructs_and_algorithm/blob/master/pictures/graph/topsort/02.jpg?raw=true

1:将BC加入到排序结果中。
    
顶点B和顶点C都是没有依赖顶点,因此将CC加入到结果集T中。假设ABCDEFG按顺序存储,因此先访问B,再访问C。访问B之后,去掉边<B,A><B,D>,并将AD加入到队列Q中。同样的,去掉边<C,F><C,G>,并将FG加入到Q中。
    (01)
B加入到排序结果中,然后去掉边<B,A><B,D>;此时,由于AD没有依赖顶点,因此并将AD加入到队列Q中。
    (02)
C加入到排序结果中,然后去掉边<C,F><C,G>;此时,由于F有依赖顶点DG有依赖顶点A,因此不对FG进行处理。
2:将A,D依次加入到排序结果中。
    
1步访问之后,A,D都是没有依赖顶点的,根据存储顺序,先访问A,然后访问D。访问之后,删除顶点A和顶点D的出边。
3:将E,F,G依次加入到排序结果中。

因此访问顺序是:B -> C -> A -> D -> E -> F -> G

 

http://10.10.21.57/problem/333《神秘岛》为例:

#include<bits/stdc++.h>
using namespace std;

int n,p;
int c[300]={},u[300]={};
int a[300][300];
int into[300]={},out[300]={};
int que[300];

void read()//读入

    memset(a,10,sizeof(a));
 cin>>n>>p;
 for(int i=1;i<=n;++i)//n
个点
 {
  cin>>c[i]>>u[i];
 }
 for(int i=1;i<=p;++i)//p
条有向边
 {
  int x,y,z;
  cin>>x>>y>>z;
  a[x][y]=z;
  out[x]++;//
出度++
  into[y]++;//
入度++
 }

}

void topsort()
{
 int h=0,t=0;
 for(int i=1;i<=n;++i)//
让入度为0的点(起点)按编号大小(其实无所谓顺序,只不过for循环从小到大而已)进队
 {
  if(into[i]==0)
    que[++t]=i;//
1开始存,存完后t指向最后一个编号
 }
 while(h++<t)//
如果h<th++,然后执行while{...}
 {
  for(int k=1;k<=n;++k)
  {
   if(a[que[h]/*
第一个起点*/][k]<=1000000)//如果<1000000就说明从点que[h]到点k有边
   {
    into[k]--;//k
入度--
    if(c[que[h]]>0)
    {
     c[k]=c[k]+a[que[h]][k]*c[que[h]];
    }
    if(into[k]==0)//
判断点k入度是否为0,如果为0则可以进队
    {
     que[++t]=k;
     c[k]-=u[k];
    }
    
   }
  }
 }
}

void work()
{
 topsort();
 bool flag=0;
 for(int i=1;i<=n;++i)
 {
  if(out[i]==0&&c[i]>0)//
当点i没有出度(终点)并且c[i]>0(处于兴奋状态),就输出i
  cout<<i<<" "<<c[i]<<endl,flag=1;
 }
 if(!flag)
 cout<<"NULL";
}

int main()
{
 read();
 work();
 return 0;
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值