题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=4110
题目大意:
拓扑排序。
但是本题的要求不是拓扑序列字典序最小,
而是1~N号球所对应的排序后的位置构成的序列字典序最小,
也就是,在满足编号1尽量靠前的条件下,编号2要尽量靠前,在满足前两个条件下,编号3尽量靠前,依次类推。
算法:
反向思维,倒序拓扑。
每次让序号大的球尽量往后排。
因为从后往前排的时候,
决定的位置就是越来越重要的,
然后不断有新的顶点入队,
如果这里面有更小的顶点,就可以把它放到前面去。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int head[210],d[210],ans[210],top,E;
struct
{
int u,v,w,nxt;
} edge[41000];
void addedge(int u,int v)
{
edge[E].u=u;
edge[E].v=v;
edge[E].nxt=head[u];
head[u]=E++;
}
int main()
{
int n,m,cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
memset(d,0,sizeof(d));
E=0;
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(v,u);
d[u]++;
}
priority_queue<int>qq;
for(int i=1; i<=n; i++)
{
if(!d[i])
qq.push(i);
}
top=n;
while(!qq.empty())
{
int u=qq.top();
qq.pop();
ans[u]=top--;
for(int i=head[u]; i!=-1; i=edge[i].nxt)
{
d[edge[i].v]--;
if(!d[edge[i].v])
qq.push(edge[i].v);
}
}
if(top)
{
puts("-1\n");
continue;
}
for(int i=1; i<=n; i++)
{
if(i>1)putchar(' ');
printf("%d",ans[i]);
}
puts("\n");
}
return 0;
}
本文介绍了一种特殊的拓扑排序问题,要求1~N号节点在排序后的字典序最小。采用反向思维,通过倒序拓扑排序的方式解决该问题,并提供了详细的算法思路与C++代码实现。
9万+

被折叠的 条评论
为什么被折叠?



