拓扑排序指的是有向无环图(DAG);
学过计算机网络的知道计算机网络中有一个拓扑结构;
下面就是一个拓扑结构;
那拓扑序就是,图中任意一对顶点u和v,若边∈E(G),则u在线性序列中出现在v之前
我们可以发现拓扑序不是唯一的;
接下来,我们需要知道一个概念——度:
对于有向图的某个结点来说,我们把指向它的边的数量叫做入度;
把从它发出的边的数量称为出度,这个都很好理解吧;
如何获得一个拓扑序:
我们先来找一个最容易理解的例子,那就是食物链,对一个自然界的食物链来说,一定存在拓扑序;
第一:不存在环;
第二:有向;
接下来我们来看看如何获得一个拓扑序,我们观察最左面的结点,一定是没有指向它的边,也就是入度为零,最右边的结点呢,是一定不存在它指向别人的边的,如果有,那么它就不是最右边的点也就是出度为零;
那就是说,所有入度为零的点都可以作为起点,我们开一个数组记录入度的值;
至于如何使用邻接表存边,这就不展开解释了,可以参考这个:传送门
其实,拓扑排序也是bfs的一个简单应用,我们需要借助队列来实现;
首先,我们遍历存储入度的数组,获得可以作为起点的结点,将其加入队列;
接下来就可以愉快的遍历了,没当我们遍历到一个点的时候,我们让它的入度--;
这样做的意义就是,判断指向这个点的边是不是都遍历过了,因为我们要保证拓扑序最重要的一个特点:的边中,u一定在v的前面出现;
如果这个点所有的边都遍历过的话,是不是也就是说这个点已经没有指向它的边了,也就是说这个点可以作为一个起点了,那我们将它加入队列;循环这个操作,知道队列为空;
最大食物链计数 - 洛谷
有了上面的介绍,我们直接来看这个题;我们要求最大食物链数量;
这个最大,我们不要理解错了,这个指的就是,我们需要从一个入度为零的点开始到一个出度为零的点;计算给出的食物网中,食物链的数量;
这里题,我们需要不仅需要记录一下入度还要记录一下出度,因为我们要计算食物链的数量,食物链的最后一个结点,是不是就是出度为零的点;
然后食物链的数量的话,是不是就是一个简答的dp啊;然后我们这个题就做完了;
#include
#include
#include
#include
#include
#define x first
#define y second
#define _for(i,s,t) for(int i = (s);i <=t ; i++)
#define FAST ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair PII;
const int N = 5010,M = 500010,INF = 0x3f3f3f3f,mod = 80112002;
int h[N],e[M],ne[M],idx;
int d[N],c[N],f[N],q[N];
int n,m;
void add(int a,int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void topsort()
{
int hh = 0,tt = -1;
for(int i =1 ;i<= n;i++)
{
if(!d[i])
{
q[++tt] = i;
f[i] = 1;
}
}
while(hh <= tt)
{
int t = q[hh++];
for(int i = h[t]; i!= -1 ; i = ne[i])
{
int j = e[i];
d[j]--;
f[j] = (f[j] + f[t]) % mod;
if(d[j] == 0)q[++tt] = j;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
for(int i = 1 ;i<= m ;i ++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
d[b]++,c[a]++;
}
topsort();
int res = 0;
for(int i = 1; i<= n ;i++)
{
if(!c[i])
{
res = (res + f[i]) % mod;
}
}
printf("%d",res);
return 0;
}
旅行计划 - 洛谷
这个题,我们根据题意是不是知道这个是一个DAG,我们需要计算的是以城市 i 为终点最多能够游览多少个城市;这个是不是也是在一个拓扑序上做一个简单的dp就行了,我们记录一下最大值即可;
#include
#include
#include
#include
#include
#define x first
#define y second
#define _for(i,s,t) for(int i = (s);i <=t ; i++)
#define FAST ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair PII;
const int N = 100010,M = 2 * N ,INF = 0x3f3f3f3f;
int n,m;
int h[N],e[M],ne[M],idx;
int d[N],q[N],f[N];
int hh = 0, tt = -1;
void add(int a,int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
void topsort()
{
for(int i =1 ;i<= n ;i ++)
{
if(!d[i])
{
q[++tt] = i;
f[i] = 1;
}
}
while(hh <= tt)
{
int t = q[hh++];
for(int i =h[t]; i != -1 ;i = ne[i])
{
int j = e[i];
f[j] = max(f[j] , f[t] + 1);
d[j]--;
if(d[j] == 0)q[++tt] = j;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
for(int i = 1;i <= m ;i ++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
d[b] ++;
}
topsort();
for(int i =1; i<= n; i++)
{
printf("%d\n",f[i]);
}
return 0;
}