H国有n个城市,城市与城市之间有m条单向道路,满足任何城市不能通过某条路径回到自己。
现在国王想给城市重新编号,令第i个城市的新的编号为a[i],满足所有城市的新的编号都互不相同,并且编号为[1,n]之间的整数。国王认为一个编号方案是优美的当且仅当对于任意的两个城市i,j,如果i能够到达j,那么a[i]应当<a[j]。
优美的编号方案有很多种,国王希望使1号城市的编号尽可能小,在此前提下,使得2号城市的编号尽可能小...依此类推。
【题解】
反向建图,拓扑排序时每次选取入度为0的编号最大的节点,最后反向输出,注意题目所求的不是1-n编号对应的城市而是1-n城市对应的编号,编号最大节点使用优先队列维护。
【代码】
program escape; var t, o: longint; a: array[-1..200001, 1..2] of longint; b: array[-1..300000] of longint; i, j, k, n, m: longint; c: array[0..300000] of longint; cd: array[-1..300000] of longint; d: array[-1..300000] of longint; e: array[-1..300000] of longint; procedure qsort(x, y: longint); var i, j, m1, m2, t: longint; begin i := x; j := y; m1 := a[(i + j) div 2, 2]; m2 := a[(i + j) div 2, 1]; repeat while (a[i, 2] < m1) or ((a[i, 2] = m1) and (a[i, 1] < m2)) do Inc(i); while (a[j, 2] > m1) or ((a[j, 2] = m1) and (a[j, 1] > m2)) do Dec(j); if i <= j then begin t := a[i, 1]; a[i, 1] := a[j, 1]; a[j, 1] := t; t := a[i, 2]; a[i, 2] := a[j, 2]; a[j, 2] := t; Inc(i); Dec(j); end; until i > j; if i < y then qsort(i, y); if j > x then qsort(x, j); end; procedure hup(m: longint); var i: longint; t: longint; begin i := m div 2; while i <> 0 do begin if c[m] < c[i] then break else begin t:=c[m]; c[m]:=c[i]; c[i]:=t; m := i; i := m div 2; end; end; end; procedure hdown(i: longint); var j: longint; t: longint; begin if c[i * 2] < c[i * 2 + 1] then j := i * 2 + 1 else j := i * 2; if (i * 2 + 1 > c[0]) and (j = i*2+1) then Dec(j); while (c[i] < c[j]) and (j <= c[0]) do begin t:=c[i]; c[i]:=c[j]; c[j]:=t; i := j; if c[i * 2] < c[i * 2 + 1] then j := i * 2 + 1 else j := i * 2; if (i * 2 + 1 > c[0]) and (j = i*2+1) then Dec(j); //堆操作不能忘了这句话- - end; end; procedure insert(x: longint); begin Inc(c[0]); c[c[0]] := x; hup(c[0]); end; function top: longint; var t: longint; begin top := c[1]; t := c[1]; c[1] := c[c[0]]; c[c[0]] := t; Dec(c[0]); hdown(1); end; begin readln(n, m); for i := 1 to m do readln(a[i, 1], a[i, 2]); a[m + 1, 2] := 0; c[0] := 0; qsort(1, m); for i := 1 to n do b[i] := 0; for i := 1 to n do cd[i] := 0; for i := 1 to m do if b[a[i, 2]] = 0 then b[a[i, 2]] := i; for i := 1 to m do Inc(cd[a[i, 1]]); for i := 1 to n do if cd[i] = 0 then insert(i); if (c[0] = 0) then writeln(-1) else for i := 1 to n do begin k := top; d[n - i + 1] := k; e[d[n - i + 1]] := n - i + 1; j := b[k]; while a[j, 2] = k do begin Dec(cd[a[j, 1]]); if cd[a[j, 1]] = 0 then insert(a[j, 1]); Inc(j); end; if (i <> n) and (c[0] = 0) then begin writeln(-1); break; end; if i = n then begin for j := 1 to n - 1 do Write(e[j], ' '); writeln(e[n]); end; end; end.
【Vijos1790】拓扑编号
最新推荐文章于 2016-11-14 19:52:00 发布