描述
H国有n个城市,城市与城市之间有m条单向道路,满足任何城市不能通过某条路径回到自己。现在国王想给城市重新编号,令第i个城市的新的编号为a[i],满足所有城市的新的编号都互不相同,并且编号为[1,n]之间的整数。国王认为一个编号方案是优美的当且仅当对于任意的两个城市i,j,如果i能够到达j,那么a[i]应当<a[j]。
优美的编号方案有很多种,国王希望使1号城市的编号尽可能小,在此前提下,使得2号城市的编号尽可能小...依此类推。
格式
输入格式
第一行读入n,m,表示n个城市,m条有向路径。
接下来读入m行,每行两个整数:x,y
表示第x个城市到第y个城市有一条有向路径。
输出格式
输出一行:n个整数
第i个整数表示第i个城市的新编号a[i],输出应保证是一个关于1到n的排列。
限制
每个测试点1s
提示
30%的测试点满足:n <= 10, m <= 10
70%的测试点满足:n <= 1000, m <= 10000
100%的测试点满足:n <= 100000, m <= 200000
输入数据可能有重边,可能不连通,但保证是有向无环图。
来源
Topcode
分析:拓扑排序+堆优化
从前向后找每次找到序号最小的入度为0的点?样例就不对。(脑补一下为什么。。。)
从后向前反向贪心?可行。每次找出度为0的编号最大的点,删反向边,减出度,并令这个点的编号当前最大。
一个有向无环图中出度为0的点一定在最后,那么根据序号大小从大到小编号,保证小编号一定留给序号小的且尽量靠前的点。
Code:
program t;
var n,m,i,x,y,l,j,p:longint;
head,c,ans:array[1..100000]of longint;
edge:array[1..200000,1..2]of longint;
begin
read(n,m);
for i:=1 to n do head[i]:=-1;
for i:=1 to m do
begin
read(x,y);
l:=l+1;
edge[l,1]:=x;
edge[l,2]:=head[y];
head[y]:=l;
c[x]:=c[x]+1;
end;
for i:=n downto 1 do
begin
j:=n;
while (j>0)and(c[j]<>0) do j:=j-1;
ans[j]:=i;
c[j]:=n+1;
p:=head[j];
while p<>-1 do
begin
c[edge[p,1]]:=c[edge[p,1]]-1;
p:=edge[p,2];
end;
end;
for i:=1 to n do write(ans[i],' ');
end.
但这题的数据范围是100000拓扑排序复杂度O(n^2)
在每次找出度为0的点时用堆优化,复杂度O(nlogn)
Code:
program tt;
var n,m,i,x,y,l,j,p:longint;
head,c,ans,heap:array[1..100000]of longint;
edge:array[1..200000,1..2]of longint;
procedure add(x:longint);
var i,j,t:longint;
begin
heap[l]:=x;
i:=l;
while i>1 do
begin
j:=i shr 1;
if heap[j]<heap[i] then
begin
t:=heap[j];heap[j]:=heap[i];heap[i]:=t;
i:=j;
end
else
break;
end;
end;
procedure updata;
var i,j,t:longint;
begin
i:=1;
while i shl 1<=l do
begin
j:=i shl 1;
if (j<l)and(heap[j]<heap[j+1]) then j:=j+1;
if heap[i]<heap[j] then
begin
t:=heap[i];heap[i]:=heap[j];heap[j]:=t;
i:=j;
end
else
break;
end;
end;
begin
read(n,m);
for i:=1 to n do head[i]:=-1;
for i:=1 to m do
begin
read(x,y);
l:=l+1;
edge[l,1]:=x;
edge[l,2]:=head[y];
head[y]:=l;
c[x]:=c[x]+1;
end;
for i:=1 to n do
if c[i]=0 then
begin
l:=l+1;
add(i);
end;
for i:=n downto 1 do
begin
j:=heap[1];//每次加入度为0的点,用大根堆维护编号
ans[j]:=i;
c[j]:=n+1;
heap[1]:=heap[l];l:=l-1;updata;
p:=head[j];
while p<>-1 do
begin
c[edge[p,1]]:=c[edge[p,1]]-1;
if c[edge[p,1]]=0 then begin l:=l+1;add(edge[p,1]);end;
p:=edge[p,2];
end;
end;
for i:=1 to n do write(ans[i],' ');
end.