查错 (拓扑排序+堆维护)

查错
[Description]
一天,考试题神坑了。不过,我们的Mosaic还是成功的写出了程序,当然,结果比较赞:“TBMW*TBMW*”,结果被痛骂了一顿。经过漫长的检查,Mosaic发现他的程序有M处错误,现在要做的就是修改程序了。但是他发现,这M处错误存在复杂的联系,有的错误必须在其他错误之前改正,否则事情会变得很麻烦,因此,他开始写另一个程序来解决这个问题……

[Input]
第一行两个整数:M,N。N表示程序之间的依赖关系数量
以下N行每行两个整数a,b。表示第a处错误必须在第b处错误之前改正。

[Output]
一行,按改正顺序输出错误编号。若有多解,请输出字典序小的解(即尽量使编号小的错误先被改正)。如果无解,输出“OMG.”(不含引号)。

[Sample]
Sample Input
5 5
1 2
2 3
1 3
1 4
4 5
Sample Output
1 2 3 4 5

[Hint]
对于100%的数据,有0 < M,N ≤ 100000
保证没有重边。

感谢姜大神的标程让我学会了拓扑排序(以前对于topsort一窍不通),而且这道题的数据比较大,需要堆维护,很经典。 我们首先建边,记录每个点的入度,把每一个入度为零的点(其实就是目前可以做的任务)放进堆里进行维护。然后每一次都弹出堆里面的第一个元素,当这个元素出堆之后,所有必须在他之后的任务的入度都要减一,如果有些任务的入度减到0了,那么将这个任务入堆。反复的弹出第一个任务并且记录弹出元素的数量,然后删边,维护堆,直到堆里不再有元素。如果弹出的元素数量小于点数,那就说明有些任务不能完成,输出OMG,否则按顺序输出弹出的元素即可。

program mys;
type ab=^node;
node=record
ends:longint;
next:ab;
end;

var i,j,k,m,n,chu,t,x,y:longint;
p:array[0..200000]of ab;
f,a,d:array[0..200000]of longint;

procedure com(x,y:longint);
var i:ab;
begin 
i:=p[x];
new(p[x]);
p[x]^.ends:=y;
p[x]^.next:=i;
end;

procedure put(x:longint);
var i,j,k,g,h:longint;
begin
inc(t);
f[t]:=x;
j:=t;
i:=j div 2;
while (f[i]>f[j]) and (j>1) do
begin
k:=f[j]; f[j]:=f[i]; f[i]:=k;
j:=i;
i:=j div 2;
end;
end;

function get:longint;
var ff,son,p:longint;
begin 
get:=f[1];
f[1]:=f[t];
dec(t);
ff:=1;
while ff*2<=t do 
begin 
if (ff*2+1>t)or(f[ff*2]<f[ff*2+1]) then 
son:=ff*2
else son:=ff*2+1;
if f[ff]>f[son] then
begin
p:=f[ff]; f[ff]:=f[son]; f[son]:=p;
end;
ff:=son;
end;
end;

procedure fa;
var i:ab;
y,x:longint;
begin 
if t>0 then 
repeat
x:=get;
inc(chu);
a[chu]:=x;
i:=p[x];
while i<>nil do 
begin 
y:=i^.ends;
dec(d[y]);
if d[y]=0 then put(y);
i:=i^.next;
end;
p[x]:=nil;
until t<=0;
end;

begin 
assign(input,'correct.in'); reset(input);
assign(output,'correct.out'); rewrite(output);
readln(n,m);
for i:=1 to m do 
begin 
readln(x,y);
com(x,y);
inc(d[y]);
end;
for i:=1 to n do 
if d[i]=0 then put(i);
chu:=0;
fa;
if chu<n then 
begin 
writeln('OMG.'); 
close(input); 
close(output);
end;
for i:=1 to chu-1 do 
write(a[i],' ');
write(a[chu]);
close(input);
close(output);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值