spoj p104 Matrix-Tree定理

  这个问题就是经典的生成树记数问题,题目为spoj p104 highway。

  首先我们引入Matrix-Tree定理,由kirchhoff证明,定理的概述为,对于图G,我们定义若干个矩阵,

    D[G],Dij=(i!=j)?0:vi;这里vi为节点i的度数。

    A[G],Aij=存在边(u,v),即A为图G的连通01矩阵。

    定义Kirchhoff Matrix C[G]=D[G]-A[G],那么C[G]的任意一个n-1阶主子式的行列式的绝对值为图G生成树个数。

这样这个问题就可以比较容易的解决了,行列式的求法为将矩阵用类似于消元的方法消成上三角矩阵(其实我也是记住的代码= =)。

//By BLADEVIL

#include <cstdio>

#include <cstring>

#define maxn 20



using namespace std;



int a[maxn][maxn];

double g[maxn][maxn];



bool zero(double x)

{

    return (((x<0)?-x:x)<1e-15);

}



void swap(double &a,double &b)

{double c=a;a=b;b=c;}



double delte(double a[maxn][maxn],int n)

{

    int sign=0;

    double ans=1;

    for (int i=1;i<=n;i++)

    {

        if (zero(a[i][i]))

        {

            int j;

            for (j=i+1;(j<=n)&&(zero(a[j][i]));j++);

            if (j>n) return 0;

            for (int k=i+1;k<=n;k++) swap(a[i][k],a[j][k]);

            sign++;

        }

        ans*=a[i][i];

        for (int j=i+1;j<=n;j++) a[i][j]/=a[i][i];

        for (int j=i+1;j<=n;j++)

            for (int k=i+1;k<=n;k++)

                a[j][k]-=a[i][j]*a[k][i];

    }

    if (sign&1) ans=-ans;

    return ans;

}



void solve()

{

    int n,m;

    scanf("%d%d",&n,&m);

    memset(g,0,sizeof g); memset(a,0,sizeof a);

    for (int i=1;i<=m;i++)

    {

        int x,y;

        scanf("%d%d",&x,&y);

        a[x][y]=a[y][x]=1;

        g[x][x]++; g[y][y]++;

    }

    n--;

    for (int i=1;i<=n;i++)

        for (int j=1;j<=n;j++)

            if (a[i][j]) g[i][j]=-1;

    printf("%.0f\n",delte(g,n));

}



int main()

{

    int task;

    scanf("%d",&task);

    while (task--) solve();

    return 0;

}

 

你可能感兴趣的:(Matrix)