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(将n从Q中删掉),并放入T(将n加入到结果集中);
3.2 对n每一个邻接点m(n是起点,m是终点);
3.2.1 去掉边<n,m>;
3.2.2 如果m没有依赖顶点,则把m放入Q;
注:顶点A没有依赖顶点,是指不存在以A为终点的边。
以上图为例,来对拓扑排序进行演示。
第1步:将B和C加入到排序结果中。
顶点B和顶点C都是没有依赖顶点,因此将C和C加入到结果集T中。假设ABCDEFG按顺序存储,因此先访问B,再访问C。访问B之后,去掉边<B,A>和<B,D>,并将A和D加入到队列Q中。同样的,去掉边<C,F>和<C,G>,并将F和G加入到Q中。
(01) 将B加入到排序结果中,然后去掉边<B,A>和<B,D>;此时,由于A和D没有依赖顶点,因此并将A和D加入到队列Q中。
(02) 将C加入到排序结果中,然后去掉边<C,F>和<C,G>;此时,由于F有依赖顶点D,G有依赖顶点A,因此不对F和G进行处理。
第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<t,h++,然后执行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;
}