什么是拓扑排序?
拓扑排序是一种有向无环图(DAG)的顶点排序方法,它将一个有向无环图中的所有顶点排成一个线性序列,使得图中任意一条有向边上的起点排在终点的前面。
拓扑排序步骤以及模板
首先建立一个空队列,将所有入度为0的点加进队列,然后用邻接矩阵一个个枚举,将枚举出来的点入度减1,如果减到0,再加进队列。
拓扑排序还可以判断是否存在环,把所有枚举出来的数与原来所有点比较,如果长度小于点的数量,则存在环。
void topo(){
queue<int>q;
for(int i=1;i<=n;i++){
if(!ind[i])q.push(i);
}
while(!q.empty()){
int x=q.front();
q.pop();
for(const auto &y:g[x]){
ind[y]--;
if(!ind[y])q.push(y);
}
}
}
例题:
家谱树
该题就是拓扑排序的模板
代码附上:
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int ind[N];
vector<int>g[N];
int n;
void topo(){
queue<int>q;
for(int i=1;i<=n;i++){
if(!ind[i])q.push(i);
}
while(!q.empty()){
int x=q.front();
q.pop();
cout<<x<<" ";
for(const auto &y:g[x]){
ind[y]--;
if(!ind[y])q.push(y);
}
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
int x;
while(cin>>x&&x!=0){
g[i].push_back(x);
ind[x]++;
}
}
topo();
return 0;
}
奖金
我认为员工 a 的奖金应该比 b 高
从这句话中我们可以建一条从b到a的有向边,是在b的基础上+1到a所以建边由b到a
判断 Poor Xed:即判断是否存在环,可通过拓扑排序后一个个枚举入度是否为0,如果有个点入度不为0,则存在环。
至于奖金如何算,简单的dp问题 f[y]=max(f[y],f[x]+1);
注意初始化,每个人奖金初始为100。
代码附上:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int ind[N],f[N];
vector<int>g[N];
int n,m;
void topo(){
queue<int>q;
for(int i=1;i<=n;i++){
if(!ind[i]){
q.push(i);
}
}
while(!q.empty()){
int x=q.front();
q.pop();
for(const auto &y:g[x]){
f[y]=max(f[x]+1,f[y]);
ind[y]--;
if(!ind[y]){
q.push(y);
}
}
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)f[i]=100;
for(int i=1;i<=m;i++){
int x,y;cin>>x>>y;
g[y].push_back(x);
ind[x]++;
}
topo();
int sum=0;
for(int i=1;i<=n;i++){
sum+=f[i];
}
bool flag=true;
for(int i=1;i<=n;i++){
if(ind[i])flag=false;
}
if(!flag)cout<<"Poor Xed"<<"\n";
else {
cout<<sum<<"\n";
}
return 0;
}