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;
}

 

posted on 2014-02-16 23:05  BLADEVIL  阅读(315)  评论(0编辑  收藏  举报