zoukankan      html  css  js  c++  java
  • hdu 5195 DZY Loves Topological Sorting 线段树+拓扑排序

    DZY Loves Topological Sorting

    Time Limit: 1 Sec  Memory Limit: 256 MB

    题目连接

    http://acm.hdu.edu.cn/showproblem.php?pid=5195

    Description

    A topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge (uv) from vertex u to vertex v, u comes before v in the ordering.
    Now, DZY has a directed acyclic graph(DAG). You should find the lexicographically largest topological ordering after erasing at most k edges from the graph.

    Input

    The input consists several test cases. (TestCase≤5)
    The first line, three integers n,m,k(1≤n,m≤105,0≤k≤m).
    Each of the next m lines has two integers: u,v(u≠v,1≤u,v≤n), representing a direct edge(u→v).

    Output

    For each test case, output the lexicographically largest topological ordering.
     

    Sample Input

    5 5 2
    1 2
    4 5
    2 4
    3 4
    2 3
    3 2 0
    1 2
    1 3

    Sample Output

    5 3 1 2 4
    1 3 2



    HINT

    题意

    DZY有一张有向无环图(DAG),你要在最多删去k条边之后,求出字典序最大的拓扑序列。

    图的拓扑序:

    一张有向图的拓扑序列是图中点的一个排列,满足对于图中的每条有向边(u→v) 从 u 到 v,都满足u在排列中出现在v之前。

    题解:

    定义k为可以删除的边的上限

    我一开始先考虑k=0的情况(即没有边被删),这样我想可以先加一个虚点,连接每一个入度为0的点,然后从这个虚点开始dfs,每次将边按照连接点的大小排序,然后依次扫描,如果其入度为1就继续dfs,否则其入度减一。

    顺着这个思路我发现,完全不知道删除哪条边。所以只能弃疗了。

    看了题解发现了一种神奇的方法。我们可以贪心地将具有某种特质的点放入队列中,然后这个队列就是我们要求的拓扑序列。

    所需特质是什么呢?

    1.它的入度<=k(这样只要切断所有入边,它就可以入队啦)

    2.满足1的条件下编号最大的点

    那么我们就可以用线段树来维护了,先建一个(1,n)的线段树,记录入度最小值,问题转化成位置最右边的权值小于等于k所在的位置。

    这就是个经典模型了。没做过也没关系,其实很简单,只要判断k和右子树的最小值的关系即可,如果k更大,那么答案在右子树,否则在左子树。

    最后注意一下,每次找到一个点入队,要把所有出边所在的点入度减一。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 200050
     4 #define INF 123456789
     5 int n,m,k,w[N];
     6 vector<int>G[N];
     7 struct Tree{int l,r,min;}tr[N<<2];
     8 template<typename T>void read(T &x)
     9 {
    10   int k=0;char c=getchar();
    11   x=0;
    12   while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
    13   if(c==EOF)exit(0);
    14   while(isdigit(c))x=x*10+c-'0',c=getchar();
    15   x=k?-x:x;
    16 }
    17 void push_up(int x)
    18   {
    19     tr[x].min=min(tr[x<<1].min,tr[x<<1|1].min);
    20   }
    21 void bt(int x,int l,int r)
    22 {
    23   tr[x].l=l;tr[x].r=r;
    24   if (l==r)
    25     {
    26       tr[x].min=w[l];
    27       return;
    28     }
    29   int mid=(l+r)>>1;
    30   bt(x<<1,l,mid);
    31   bt(x<<1|1,mid+1,r);
    32   push_up(x);
    33 }
    34 int query(int x)
    35 {
    36   if (tr[x].min>k)return -1;
    37   if (tr[x].l==tr[x].r)
    38     {
    39       k-=tr[x].min;
    40       tr[x].min=INF;
    41       return tr[x].l;
    42     }
    43   int tp=query(x<<1|1);
    44   if (tp==-1)tp=query(x<<1);
    45   push_up(x);
    46   return tp;
    47 }
    48 void add(int x,int p)
    49 {
    50   if (p<=tr[x].l&&tr[x].r<=p)
    51     {
    52       tr[x].min--;
    53       return;
    54     }
    55   int mid=(tr[x].l+tr[x].r)>>1;
    56   if (p<=mid)add(x<<1,p);
    57   if (mid<p)add(x<<1|1,p);
    58   push_up(x);
    59 }
    60 void work()
    61 {
    62   read(n);read(m);read(k);
    63   memset(w,0,sizeof(w));
    64   int x,y;
    65   for(int i=1;i<=m;i++)
    66     {
    67       read(x);read(y);
    68       w[y]++;
    69       G[x].push_back(y);
    70     }
    71   bt(1,1,n);
    72   int cas=0;
    73   for(int i=1;i<=n;i++)
    74     {
    75       int x=query(1);
    76       if (cas++)printf(" ");
    77       printf("%d",x);
    78       for(int i=0;i<G[x].size();i++)
    79     add(1,G[x][i]);
    80     }
    81   printf("
    ");
    82   for(int i=1;i<=n;i++)G[i].clear();
    83 }
    84 int main()
    85 {
    86   #ifndef ONLINE_JUDGE
    87   freopen("aa.in","r",stdin);
    88   #endif
    89   while(1)
    90     {
    91       work();
    92     }
    93 }
    View Code
  • 相关阅读:
    用GDB调试程序(一)
    关于“鸡脚神”的看法
    Oracle 经典SQL 专为笔试准备
    怎样设计接口?
    myeclipse6.0下载及注冊码
    VB连接Mysql数据库
    开源html5_kiwijs_helloworld
    server宕机监控、检測、报警程序(139绑定手机短信报警)monitor_down.sh
    js实现自己定义鼠标右键-------Day45
    C/C++程序猿必须熟练应用的开源项目
  • 原文地址:https://www.cnblogs.com/mmmqqdd/p/10757856.html
Copyright © 2011-2022 走看看