zoukankan      html  css  js  c++  java
  • 拓扑序列的最小字典序列

    查错

    考场上又写挂的一道签到题。。。

    我们发现这题要求得到一个最小字典序列

    显然找到所有序列然后排序是不可取的,

    那么我们不能使用平常的拓扑排序方法,怎么搞使得在每次处理拓扑顺序的时候来维护呢?

    用小根堆维护入度为0的点即可,输入的时候统计入度

    {$inline on}
    const maxn=100010;
    
    type node=record
           pos,next:longint;
    end;
    
    var heap,getin,head,ans:array[0..maxn] of longint;
        edge:array[0..maxn*2] of node;
        n,m,cnt,top:longint;
        check:boolean;
    
    procedure add(u,v:longint); inline;
    begin
        inc(cnt);
        edge[cnt].pos:=v;
        edge[cnt].next:=head[u];
        head[u]:=cnt;
    end;
    
    procedure swap(var a,b:longint); inline;
    begin
        a:=a xor b;
        b:=a xor b;
        a:=a xor b;
    end;
    
    procedure up(i:longint); inline;
    var j:longint;
    begin
        j:=i>>1;
        while j>0 do
        begin
            if heap[i]<heap[j] then
                begin
                    swap(heap[i],heap[j]);
                    i:=j;
                    j:=j>>1;
                end
            else break;
        end;
    end;
    
    procedure down(i:longint); inline;
    var j:longint;
    begin
        j:=i<<1;
        while j<=top do
            begin
                if (j<top) and (heap[j]>heap[j+1]) then inc(j);
                if heap[i]>heap[j] then
                    begin
                        swap(heap[i],heap[j]);
                        i:=j;
                        j:=j<<1;
                    end
                else break;
            end;
    end;
    
    procedure init;
    var i,x,y:longint;
    begin
        read(n,m);
        for i:=1 to m do
            begin
                read(x,y);
                add(x,y);
                inc(getin[y]);
            end;
        for i:=1 to n do
            if getin[i]=0 then
                begin
                    inc(top);
                    heap[top]:=i;
                end;
        check:=true;
    end;
    
    procedure main;
    var i,j,x,y:longint;
    begin
        for j:=1 to n do
            begin
                if (top=0) then
                    begin
                        check:=false;
                        break;
                    end;
                x:=heap[1];
                ans[j]:=x;
                swap(heap[1],heap[top]);
                dec(top);
                down(1);
                i:=head[x];
                while i<>0 do
                    begin
                        y:=edge[i].pos;
                        dec(getin[y]);
                        if getin[y]=0 then
                            begin
                                inc(top);
                                heap[top]:=y;
                                up(top);
                            end;
                        i:=edge[i].next;
                    end;
            end;
    end;
    
    procedure print;
    var i:longint;
    begin
        if not check then writeln('OMG.')
        else 
            begin
                for i:=1 to n-1 do
                write(ans[i],' ');
                writeln(ans[n]);
            end;
    end;
    
    begin
        init;
        main;
        print;
    end.
    View Code

     

  • 相关阅读:
    数1的个数
    找水王2
    书店促销
    返回一个二维整数数组中最大联通子数组的和
    敏捷软件开发读书笔记(三)
    软件工程团队开发——第一次冲刺会议总结
    返回一个二维整数数组中最大联通子数组的和
    结对项目开发电梯调度
    《最后期限》——读书笔记03
    最后期限——阅读笔记2
  • 原文地址:https://www.cnblogs.com/logichandsome/p/4068359.html
Copyright © 2011-2022 走看看