zoukankan      html  css  js  c++  java
  • 删边

    删边

      昨天$asuldb$问了我一道题,那道题很神奇.要动态的维护一棵最小生成树,有时还需要删掉一些边,这就出现了一系列的问题.因为总的边数非常多,删边的时候如果使用所谓的"惰性删除",也就是打一个标记表示这条边被删掉了,就会极大地降低效率,因为每次在生成树上找环时会访问很多的无效边,所以必须动态地删除才可以,可是...网上似乎没有这方面的资料?

      图论中有删除操作的不多,比较典型的就是欧拉回路中走过去要删掉,但是那种做法似乎不是很适合这道题...还有$LCT$

      有一种最简单的方法:邻接矩阵存图,可以非常方便的实现$O(1)$删除,而且删反向边也极其简单.$g[x][y]=g[y][x]=0$.不过这种方法的局限性也是非常明显的,毕竟大多数图论题的图都是比较稀疏的,空间也开不下.

      另一种比较$C++$的方法:采用$vector$存边,可以做到$O(N)$的删除,对于那道题来说就很够用了,因为每次在树上$dfs$也已经有了$O(N)$的复杂度.

      但是!经过一节课的修改和试验,我发现了一种真正的$O(1)$删边方法,而且非常的简单,还可以删相应的反向边,这一点第二个做法似乎是做不到的.这种方法是基于链式前向星存图的,因为这种做法本质上就是$N$个链表来存边,而链表的删除就是常规操作了.注意如果当前的边是这个点发出的第一条边要特殊处理一下.所以这个为什么想了一节课...突然发现真的好简单啊...

      关于反向边的删除:其实非常的简单,就是利用网络流的技巧,边集数组从$0$开始计数,那每条边相对应的反向边就是$iquad xorquad  1$.用一样的方法删掉就好啦.

      刚刚想到的奇怪做法:依旧使用惰性删除,但是每加入$m$条边就将所有边删去进行重构,有点像替罪羊树的感觉(虽然我不会),可能也可以将复杂度保持在一个看得过去的复杂度上.

      
     1 void add (int x,int y)
     2 {
     3     t[++h].too=y;
     4     t[h].fro=x;
     5     t[ firs[x] ].pre=h;
     6     t[h].nex=firs[x];
     7     firs[x]=h;
     8 }
     9 
    10 void del (int id)
    11 {
    12     if(t[id].pre)
    13     {
    14         t[ t[id].pre ].nex=t[id].nex;   
    15         t[ t[id].nex ].pre=t[id].pre;
    16     }
    17     else
    18     {
    19         firs[ t[id].fro ]=t[id].nex;
    20         t[ t[id].nex ].pre=0;
    21     }
    22 }
    23 
    24 void print_ed()
    25 {
    26     printf("
    ");
    27     for (R i=1;i<=n;++i)
    28     {
    29         printf("%d->",i);
    30         for (R j=firs[i];j;j=t[j].nex)
    31             printf("%d ",t[j].too);
    32         printf("
    ");
    33     }
    34     printf("
    ");
    35 }
    删边

     

      ---shzr

  • 相关阅读:
    为什么叫Windows 7 ?
    关于多线程生命周期原理
    关于浏览器创建XMLHttpRequest对象
    关于ajax异步加载XML例子
    关于多线程简单原理
    指针和指针的引用
    linux学习点滴
    GCC,GDB,Makefile
    妙语集锦
    uc/os内存管理的理解
  • 原文地址:https://www.cnblogs.com/shzr/p/9798202.html
Copyright © 2011-2022 走看看