zoukankan      html  css  js  c++  java
  • 连通问题

      写一段程序以实现“给出两点,判断其是否连通”。

      这个题目可以应用于很多实际问题,如:两个城市间是否有铁路相连,两个电子元件是否有电路相连,两个终端是否有网络相连……此算法仅仅判断是否连通,如果还要求给出连通的具体路径,难度将陡然增加,并且会把问题引入另一个领域——图。

    我的第一感觉是把所有节点用一个二维数组存储。在草纸上稍加勾画后便会发现几个问题:

      1)        对于N个节点,需要N * N 个空间存储,当连通较少时大量的空间将会闲置,无论任何时候,浪费都是一种罪过;

      2)        实现困难,不信的话就自己试试吧;

      3)        这毫无疑问是最糟糕的方法。

      其实稍加思考可以将空间减少指数级:用一维数组构造连通器,如果节点p、q连通,则令id[p] == id[q]。

      下面是代码片段:

     1 public abstract class Arithmetic {  
     2   
     3     protected int id[] = new int[Constant.N];  
     4       
     5     public Arithmetic() {  
     6         init();  
     7     }  
     8       
     9     private void init() {  
    10         for(int i = 0; i < Constant.N; i++) {  
    11             id[i] = i;  
    12         }  
    13     }  
    14   
    15     public abstract void createConnect(int p, int q);  
    16       
    17     public abstract boolean isConnect(int p, int q);  
    18 }  
    19 
    20 public class Arithmetic_1 extends Arithmetic {  
    21   
    22     public Arithmetic_1() {  
    23         super();  
    24     }  
    25   
    26     @Override  
    27     public void createConnect(int p, int q) {  
    28         int t = id[p];  
    29         for(int i = 0; i < Constant.N; i++) {  
    30             if(id[i] == t)  
    31                 id[i] = id[q];  
    32         }  
    33     }  
    34       
    35     @Override  
    36     public boolean isConnect(int p, int q) {  
    37         return id[p] == id[q];  
    38     }  
    39 }  

      上面的代码可以解决一下小问题。当我试着对10,000个顺序自然数构随机构造10,000次连通时,它花了我一杯咖啡的时间!估计再增加一个0,想要得到结果就得等到“中国老百姓看病最不难”那天真正来临。

      分析一下效率就知道,对N个数的M次连通,每次构造连通器都会花费N次循环,效率是N*M。如果看成一棵树的话,每次构造连通都将把整棵树毁掉,然后重新打造;如果把两个棵树合并,则需要同时毁掉两棵树,这可真够呛!

      把两棵树合并的最简方法就是直接把树根合并,按照这个思路改进的代码如下:

     1 public void createConnect(int p, int q) {  
     2   
     3     int i,j;  
     4     for(i = p; i != id[i]; i = id[i]);  
     5     for(j = q; j != id[j]; j = id[j]);  
     6               
     7     if(i != j)  
     8         id[i] = j;  
     9 }  
    10   
    11 public boolean isConnect(int p, int q) {  
    12           
    13     int i,j;  
    14     for(i = p; i != id[i]; i = id[i]);  
    15     for(j = q; j != id[j]; j = id[j]);  
    16           
    17     return i == j;  
    18 }  

      通过指针追溯的方式回答两点是否连通。

      同样对10,000个顺序自然数构随机构造10,000次连通的测试,虽然可以马上产生连通器,但是在判断是否连通时花费了一些时间,对于大数据的实践,这个算法同样不适用。

      方法二的结果似乎严重依赖输入,它通常枝繁叶茂,但有可能变得比摩天大楼还高,而且营养不良,正是这点严重影响了isConnect的效率。

      如果你的方法可以改进,那么它通常可以进一步改进。接下来要做的就是使摩天大楼变成古老的中式建筑群。很简单,在方法二的基础上为树加权,使用另外一个数组sz[]来维护每棵连通树的节点个数,每次合并都会将较小的树连接到较大的树上。

     1 private int sz[] = new int[Constant.N];  
     2       
     3     public Arithmetic_3() {  
     4         super();  
     5           
     6         for(int i = 0; i < Constant.N; i++)  
     7             sz[i] = 1;  
     8     }  
     9   
    10     @Override  
    11     public void createConnect(int p, int q) {  
    12   
    13         int i,j;  
    14         for(i = p; i != id[i]; i = id[i]);  
    15         for(j = q; j != id[j]; j = id[j]);  
    16           
    17         if(i != j) {  
    18             //将较小的树连接到较大的树上  
    19             if(sz[i] < sz[j]) {  
    20                 id[i] = j;  
    21                 sz[j] += sz[i];  
    22             }  
    23             else {  
    24                 id[j] = i;  
    25                 sz[i] += sz[j];  
    26             }  
    27         }  
    28     }  

      这次我甚至可以轻松的对1,000,000个顺序自然数构随机构造1,000,000次连通并很快得到两点是否连通的答案。


      作者:我是8位的

      出处:http://www.cnblogs.com/bigmonkey

      本文以学习、研究和分享为主,如需转载,请联系本人,标明作者和出处,非商业用途! 

  • 相关阅读:
    Python(93)_网络编程基础
    Web前端(13)_路径
    Web前端(12)_注释
    Web前端(11)_base标签
    Python(91)_python复习
    Web前端(10)_css文本样式
    Web前端(9)_div+span等标签
    虚拟化(6)_CPU虚拟化
    虚拟化(5)_打开tcp监听
    虚拟化(4)_离线克隆与在线克隆
  • 原文地址:https://www.cnblogs.com/bigmonkey/p/7780623.html
Copyright © 2011-2022 走看看