拓扑排序
定义:拓扑排序是指在有向无环图中,将所有的结点进行排序,最终得出的序列称为拓扑序。
先来看一个模板代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,tot=0,head[maxn],seq[maxn],d[maxn];
struct node
{
int nex,to;
}edge[maxn];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(seq,0,sizeof(seq)); //保存拓扑排序的结点
memset(d,0,sizeof(d)); //保存每个结点的入度
}
void add(int from,int to)
{
edge[++tot].to=to;
edge[tot].nex=head[from];
head[from]=tot;
}
void topsort()
{
queue<int> q;
//如果编号要按顺序输出可有priority_queue<int,vector<int>,greater<int> >
for(int i=1;i<=n;++i)
if(!d[i]) q.push(i);
int cnt=0;
while(!q.empty())
{
int u=q.front();
q.pop();
seq[++cnt]=u;
for(int i=head[u];i!=-1;i=edge[i].nex)
if(--d[edge[i].to]==0) q.push(edge[i].to);
}
if(cnt!=n){
printf("-1
"); //存在环
return;
}
for(int i=1;i<=n;++i){
printf("%d%c",seq[i],i==n?'
':' ');
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
init();
for(int i=1;i<=m;++i){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
d[v]++;
}
topsort();
}
}
【题意】:有n个小球和m个要求,所有小球的重量在1~n之间,每个要求的格式为 a b 表示a比b轻,输出最小的字典序的组合。
思路:将所有小球的出度表示出来,用大根堆的优先队列将所有小球出度为0的球装进去,每次弹出一个编号最大的将剩余的最大重量给它贪心即可;show code:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
const int maxn=210;
int od[maxn],arr[maxn][maxn],T,n,m,seq[maxn];
void topsort()
{
priority_queue<int> q;
int tot=n;
for(int i=1;i<=n;++i)
if(od[i]==0) q.push(i);
while(!q.empty())
{
int u=q.top();
q.pop();
seq[u]=tot--;
for(int i=1;i<=n;++i){
if(arr[i][u]){
od[i]--;
if(od[i]==0) q.push(i);
}
}
}
if(tot){
printf("-1
");
return;
}
for(int i=1;i<=n;++i){
printf("%d%c",seq[i],i==n?'
':' ');
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
arr[i][j]=0;
od[i]=seq[i]=0;
}
}
for(int i=1;i<=m;++i){
int a,b;
scanf("%d %d",&a,&b);
if(!arr[a][b]){
od[a]++;
arr[a][b]=1;
}
}
topsort();
}
}