【Vijos1790】拓扑编号

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.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生就业服务平台管理系统按照操作主体分为管理员和用户。管理员的功能包括学生档案管理、字典管理、试卷管理、试卷选题管理、试题表管理、考试记录表管理、答题详情表管理、错题表管理、法律法规管理、法律法规收藏管理、法律法规留言管理、就业分析管理、论坛管理、企业管理、简历管理、老师管理、简历投递管理、新闻资讯管理、新闻资讯收藏管理、新闻资讯留言管理、学生信息管理、宣传管理、学生管理、职位招聘管理、职位收藏管理、招聘咨询管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 大学生就业服务平台管理系统可以提高大学生就业服务平台信息管理问题的解决效率,优化大学生就业服务平台信息处理流程,保证大学生就业服务平台信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理新闻信息,管理大学生就业服务平台信息,包括考试管理,培训管理,投递管理,薪资管理等,可以管理新闻信息。 考试管理界面,管理员在考试管理界面中可以对界面中显示,可以对考试信息的考试状态进行查看,可以添加新的考试信息等。投递管理界面,管理员在投递管理界面中查看投递种类信息,投递描述信息,新增投递信息等。新闻信息管理界面,管理员在新闻信息管理界面中新增新闻信息,可以删除新闻信息。新闻信息类型管理界面,管理员在新闻信息类型管理界面查看新闻信息的工作状态,可以对新闻信息的数据进行导出,可以添加新新闻信息的信息,可以编辑新闻信息信息,删除新闻信息信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值