计算任意一个图生成树的个数:Kirchhoff 的Matrix Tree方法Java实现

计算任意一个图的生成树的个数,是Kirchhoff提出的理论,通常称为Matrix Tree Theorem,原理很简单:

Let G be a graph with V(G)={v1,v2,...,vn},let A={aij}be the adjacentcy matrix of G,and let C={cij}be the n*n matrix, where cij=deg vi if i=j; cij=-aij if i!=j; Then the number of spanning trees of G is the vlaue of any cofactor(余子式) of C

但是需要计算行列式的值,这里需要点小技巧,所以这里选择了LUP分解法来计算。

package trees;  

import matrix.DeterminantCalculator;  

/**
 * 计算任意一个图的生成树的个数,是Kirchhoff提出的理论,通常称为Matrix Tree Theorem
 * Let G be a graph with V(G)={v1,v2,...,vn},let A={aij}be the adjacentcy matrix of G,
 * and let C={cij}be the n*n matrix, where cij=deg vi if i=j; cij=-aij if i!=j; Then the
 * number of spanning trees of G is the vlaue of any cofactor(余子式) of C
 * @author xhw
 *
 */
public class NumberOfSpanningTree {  

    /**
     * @param args
     */
    public static void main(String[] args) {  

        double a[][]={{0,1,1,0},
                      {1,0,1,0},
                      {1,1,0,1},
                      {0,0,1,0}};
        int n=numberOfSpanningTree(a);
        System.out.println("numberOfSpanningTree:"+n);  

    }  

    public static int numberOfSpanningTree(double[][] a) {  

        double c[][]=generateKirchhoffMatrix(a);
        double confactor[][]=new double[c.length-1][c.length-1];
        for(int i=1;i<c.length;i++)
        {
            for(int j=1;j<c.length;j++)
            {
                confactor[i-1][j-1]=c[i][j];
                //System.out.print(c[i][j]+" ");
            }
            //System.out.println();
        }  

        DeterminantCalculator dc=new DeterminantCalculator();
        int n=(int)dc.det(confactor);
        return n;
    }  

    /**
     * C={cij}be the n*n matrix, where cij=deg vi if i=j; cij=-aij if i!=j
	*更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/
     * @param a
     * @return
     */
    public static double[][] generateKirchhoffMatrix(double[][] a) {  

        int length=a.length;
        double c[][]=new double[length][length];
        for(int i=0;i<length;i++)
        {
            int deg=0;
            for(int j=0;j<length;j++)
            {
                deg+=a[i][j];
                c[i][j]=-a[i][j];
            }
            c[i][i]=deg;  

        }
        return c;
    }  

}
package matrix;  

/**
 * 矩阵和可以用来快速地计算矩阵的行列式,因为det(A) = det(L) det(U),而三角矩阵的行列式就是对角线元素的乘积。如果要求L 是单位三角矩阵,Uii的乘积
 * 那么同样的方法也可以应用于LUP分解,只需乘上P的行列式,即相应置换的符号差。
 * @author xhw
 *
 */
public class DeterminantCalculator {  

    private LUPDecomposition lu;
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub  

    }  

    public DeterminantCalculator()
    {
        this.lu=new LUPDecomposition();
    }  

    public double det(double a[][])
    {
        a=lu.decomposition(a);
        if(a==null)
            return 0;
        double d=1;
        for(int i=0;i<a.length;i++)
        {
            d=d*a[i][i];
        }
        int n=lu.getExchangeTimes();
        if(n%2==0)
            return d;
        else
            return -d;
    }  

}
package matrix;  

/**
 * LUP分解
*更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/
 * P是置换矩阵,L是下三角矩阵,并且对角线为1,U是上三角矩阵;P的出现主要是为了选主元,在选取Ade非对角线元素中选主元避免除数为0,
 * 除此以外,除数的值也不能过小,否则导致计算中数值不稳定,因此所选的主元是个较大的值。详细参见算法导论P461
 * @author xhw
 *
 */
public class LUPDecomposition{  

    private int p[];
    private int exchangeTimes=0;
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub  

    }  

    public double[][] decomposition(double a[][])
    {
        int length=a.length;
        //p是置换矩阵,p[i]=j说明P的第i行第j列为1
        p=new int [length];
        for(int i=0;i<length;i++)
        {
            p[i]=i;
        }  

        for(int k=0;k<length;k++)
        {
            double max=0;
            int maxK=0;
            for(int i=k;i<length;i++)
            {
                if(Math.abs(a[i][k])>max)
                {
                    max=Math.abs(a[i][k]);
                    maxK=i;
                }
            }
            if(max==0)
            {
                System.out.println("singular matrix");
                return null;
            }
            if(k!=maxK)
            {
                //交换k和maxk行
                exchange(p,k,maxK);
                exchangeTimes++;
                for(int i=0;i<length;i++)
                {
                    double temp=a[k][i];
                    a[k][i]=a[maxK][i];
                    a[maxK][i]=temp;
                }
            }  

            //“原地”计算LU,矩阵a的上半部分为U,下半部分为L
            for(int i=k+1;i<length;i++)
            {
                a[i][k]=a[i][k]/a[k][k];
                for(int j=k+1;j<length;j++)
                {
                    a[i][j]=a[i][j]-a[i][k]*a[k][j];
                }
            }  

        }
        return a;
    }  

    public void exchange(int p[],int k,int maxK)
    {
        int temp=p[k];
        p[k]=p[maxK];
        p[maxK]=temp;
    }  

    public int[] getP() {
        return p;
    }  

    public void setP(int[] p) {
        this.p = p;
    }  

    public int getExchangeTimes() {
        return exchangeTimes;
    }  

    public void setExchangeTimes(int exchangeTimes) {
        this.exchangeTimes = exchangeTimes;
    }  

}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索matrix
, double
, 个数
, 生成
, of
The
easyui java实现tree、java 实现 merkletree、java实现tree数据结构、java实现tree、java递归实现tree删除,以便于您获取更多的相关知识。

时间: 2024-09-10 21:49:23

计算任意一个图生成树的个数:Kirchhoff 的Matrix Tree方法Java实现的相关文章

android-请问大家 有什么方法能立即监控到手机上的任意一个app打开呢?

问题描述 请问大家 有什么方法能立即监控到手机上的任意一个app打开呢? 请问大家 有什么方法能立即监控到手机上的任意一个app打开呢? 解决方案 下面的代码可以实现获取当前最上层应用的包名,可以通过循环调用此方法来定时监听手机任意APP的打开 ActivityManager mActivityManager = ( ActivityManager ) mContext.getSystemService( Context.ACTIVITY_SERVICE );// 这句话不要反复调用 List<

如何高效地计算出一个有向无环图中各个节点的祖先节点数和后代节点数?

问题描述 如何高效地计算出一个有向无环图中各个节点的祖先节点数和后代节点数? 数据量较大,希望复杂度尽量低.现在实现图的数据结构是用HashMap记录对应标号的节点,再分别对每个节点使用HashMap记录子节点.感谢!

用任意顺序开始每完成1个进程 未进行的进程任意一个开始进行 同时进行的进程个数为x个 第二种方法跟第一种类似 只是x个进程同时进行 且都已经订好位置

问题描述 usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading;namespace任务调度算法{classProgram{staticvoidMain(string[]args){Renwurw=newRenwu();rw.main();Thread.Sleep(20000);}}publicclassRenwu{publicenumstate{rea

T-SQL 2 Tips: 1.计算任意两日期之间的&amp;amp;quot;周一&amp;amp;quot;到&amp;amp;quot;周日&amp;amp;quot;分别各有几个! 2.根据出生..

这两个小技巧,不写不知道,一写吓一跳!都是看似简单,实际做起来就懵,得仔细想一想,才能写对!凡是有日期运算的程序都要细心哦! 先说第二个: 2.根据出生日期精确计算年龄!  所谓计算精确年龄就是: 生日差一天也不能长一岁!  大家常用,间隔年数算作年龄! 如果需求要精确,如: 保险 之类的,就粗了!  当然还可引申为根据入职日期计算精确的司龄,算加薪之类的需求!  我起初认为很简单,当年也写了好几遍才写对!高手们也被我晃点了数次几近晕倒!  不信有当年 2002-11-27 16:16:26 贴

Java中计算任意两个日期之间的工作天数

主要思路: 对于任意2个日期比如:date_start=2006-10-1.date_end=2006-10-14 ,首先计算这连个日期之间的时间间隔(天数),然后分别对date_start 和date_end 取得它们下一个星期一的日期,这样就可以得到一个新的可以整除7的完整日期间隔(这个新的日期间隔已经把星期几的问题剔出掉了),换一种说法就是我们可以得到,这两个新的日期之间的周数,拿这个周数乘以5就是工作日期了(tmpWorkingDays).但是这个日期并不是我们所要的日期,接下来我们要做

算法-怎么用深度优先判断一个图是否连通

问题描述 怎么用深度优先判断一个图是否连通 有一个无向图,找到相应的边,去掉这条边这个图就不是连通的.求相应算法.在线等.作业题急! 解决方案 在图论中,连通图基于连通的概念.在一个无向图G中,若从顶点v_i到顶点v_j有路径相连(当然从v_j到v_i也一定有路径),则称v_i和v_j是连通的.如果G是有向图,那么连接v_i和v_j的路径中所有的边都必须同向.如果图中任意两点都是连通的,那么图被称作连通图. 所以问题的关键是使用深度优先判断缺少某一边后图中是否任意两点连通. 一个基本的思路如下:

lua计算&quot;序列型table&quot;数据类型元素个数的&quot;诡异&quot;

序列型的table指没有气泡的一串list, 如a[1],a[2],...a[10]是一个长度为10的序列型表, 那么#a=10. 但是如果a[1],a[3],a[10]这样存储的话#a=1; 因为出现了气泡. > c={} > c[1]=10 > c[3]=1 > = #c 1 #a表示的是序列型的表数据类型的长度.  因此不难解释以下. > d={} > d[2]=10 > = #d 0 因为序列型的表的index协定是从1开始计数的. lua在计算table

给出任意一个正整数,算出大于它的最小不重复数——最高效[2014百度笔试题]

程序很简单,一看就懂,我就不多介绍了,直接上代码. /** * 给出任意一个正整数,算出大于它的最小不重复数(即不存在相邻两个数相同的情况) */ #include<iostream> using namespace std; long minNoDoubleNumber(long x) { if(x < 10) { return x; } long y = 1; long temp = x; while(temp / 10 > 0) { y *= 10; temp /= 10;

如何使用PHP计算上一个月的今天

  一日,遇到一个问题,求上一个月的今天. 最开始我们使用 strtotime("-1 month") 函数求值,发现有一个问题,月长度不一样的月份的计算结果有误. 比如:2011-03-31,得到的结果是2011-03-03.我们先不追究什么问题,先看如何解决问题. 此时,想起PHP中有一个mktime函数,于是自己写了如下代码: 代码如下: echo date("Y-m-d H:i:s", mktime(date("G", $time), d