《CI论》· 拓扑排序
Vector_Mingfan · · 个人记录
总目录
〇. 附录
Ⅰ. 定义
Ⅱ. 步骤
Ⅲ. 更新日志
〇. 附录
啊,在开始写总结之前我们先讲个故事
我们可以拿大学选课的例子来描述这个过程,比如学习大学课程中有:
如果有一天,老师说想要学习
然后你就,
我到底应该先学哪一个?当然我们在这里不考虑什么同时学几个课程的情况。在这里,
Ⅰ. 定义
| 中文名 | 拓扑排序 |
|---|---|
| 英文名 | topsort |
| 应用学科 | 计算机科学 图论 |
| 图 | 有向无环图 |
在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG)(DAG与拓扑排序的互相限制关系在链接中)
也就是这些顶点按照某种特定的优先关系进行排序,排成线性序列的过程叫做拓扑排序。
且此序列要满足一下两个要求:
步骤如下:
于是我们就可以敲出骗分版代码了(也不知道是多久打的了,但是这个代码有个极大的
#include <cstdio>
#include <algorithm>
#define N 205
using namespace std;
struct top {int to,Next;}g[N*20];
struct SORT {int now,Rdnum;}flag[N];
int n,m,x[N],y[N],cnt,h[N],rd[N],zdian[N],ans[N];
int nt,nt1;
int main() {
scanf("%d %d",&n,&m);
for (int i=1;i<=m;i++) {scanf("%d %d",&x[i],&y[i]); rd[y[i]]++;}
for (int i=1;i<=n;i++) {
if (rd[i]==0) {
nt++;
ans[i]=i;
}
else {
nt1++;
flag[i].now=i;
flag[i].Rdnum=rd[i];
}
}
for (int i=1;i<=n;i++) {
if (ans[i]) printf("%d ",ans[i]);
}
for (int i=1;i<=n;i++) {
if (flag[i].now) printf("%d ",flag[i].now);
}
}
好吧,下面贴出容易理解的代码(正码)
#include <bits/stdc++.h>
using namespace std;
const int maxx = 1001;
int n , m;
int rd[maxx] , Ans[maxx] , a[maxx][maxx] , v[maxx];
void Read() {
scanf("%d %d",&n,&m);
for (int i=1 , x , y; i<=m; i++ ) {
scanf("%d %d",&x,&y);
a[x][y] = 1;
rd[y]++ ;//入度计数
}
}
int Tsort() {
for (int i=1;i<=n;i++) {
int j=1; //从第一个点开始查找
while (j<=n&&rd[j]) j++;//寻找入度为0的点
if (j>n) return 0;
Ans[++Ans[0]] = j;
rd[j]=-1;
for (int k=1;k<=n;k++) {
if (a[j][k]) rd[k]--;//断开与j相连的边
}
}
return 1;//这是判断是否有环
}
int main() {
Read();
if (Tsort()) {
for (int i=1; i<=Ans[0]; i++ ) {
printf("%d ",Ans[i]);
}
}
else printf("no solution");
return 0;
}
看懂了上面的模板代码,我们可以进一步拓展。
对一个有向图 进行拓扑排序,是将 G 中所有顶点 排成一个线性序列,使得图中任意一对顶点 u 和 v,若 ∈E(G),则 u 在线性序列中出现在 v 之前。若图中存在有向环,则不可能使顶点满足拓扑次序。
【输入格式】
第
【输出格式】
拓扑序,顶点从
有环输出:
【输入样例
【输出样例
【输出样例
【数据范围】 100%的数据满足:1≤n≤200,1≤m≤20000,邻接矩阵即可实现。
题目完
分析:其实这道题既然要让我们,以顶点编号 大 的优先输出。其实只需要把模板里面的
while (j<=n&&rd[j]) j++;
改成
while(rd[j]&&j>=1) j--;
就完了
代码如下
#include<cstdio>
#include<iostream>
using namespace std;
bool f[201][201];int x,y,n,m,j,rd[201],a[201];
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d %d",&x,&y),f[x][y]=1,rd[y]++;
for(int i=1;i<=n;i++){
j=n;
while(rd[j]&&j>=1) j--;
if(j==0) { printf("no solution");return 0; }
a[++a[0]]=j;rd[j]=-1;
for(int k=1;k<=n;k++)
if(f[j][k]) rd[k]--;
}
for(int i=1;i<=a[0];i++) printf("%d ",a[i]);
}
懂了这些,你就可以去做这道题了【持续更新】
P2741 [USACO4.4]重叠的图像Frame Up