[spoj104][Highways] (生成树计数+矩阵树定理+高斯消元)

In some countries building highways takes a lot of time... Maybe that‘s because there are many possiblities to construct a network of highways and engineers can‘t make up their minds which one to choose. Suppose we have a list of cities that can be connected directly. Your task is to count how many ways there are to build such a network that between every two cities there exists exactly one path. Two networks differ if there are two cities that are connected directly in the first case and aren‘t in the second case. At most one highway connects two cities. No highway connects a city to itself. Highways are two-way.

Input

The input begins with the integer t, the number of test cases (equal to about 1000). Then t test cases follow. The first line of each test case contains two integers, the number of cities (1<=n<=12) and the number of direct connections between them. Each next line contains two integers a and b, which are numbers of cities that can be connected. Cities are numbered from 1 to n. Consecutive test cases are separated with one blank line.

Output

The number of ways to build the network, for every test case in a separate line. Assume that when there is only one city, the answer should be 1. The answer will fit in a signed 64-bit integer.

Example

Sample input:
4
4 5
3 4
4 2
2 3
1 2
1 3

2 1
2 1

1 0

3 3
1 2
2 3
3 1
Sample output:
8
1
1
3

Solution

学了一下矩阵树定理,用来求解生成树问题。

矩阵一树定理(matrix-tree theorem)一个计数定理.若连通图G的邻接矩阵为A,将一A的对角线(i,i)元素依次换为节点V的度d(V,),所得矩阵记为M,则M的每个代数余子式相等,且等于G的支撑树的数目.这就是矩阵一树定理.

处理行列式的话,考虑高斯消元,用初等变换把M矩阵处理为上三角矩阵X,那么X的行列式就是对角线系数之积

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#define eps 1e-20
using namespace std;
int n,m,A[15][15],B[15][15];
double a[15][15];
void gauss(){
    int now=1;
    for(int i=1;i<=n;i++){
        int x=now;
        while(fabs(a[x][now])<eps && x<=n)++x;
        if(x==n+1){puts("0");return;}
        for(int j=1;j<=n;j++)
            swap(a[now][j],a[x][j]);
        for(int j=now+1;j<=n;j++){
            double x=a[j][now]/a[now][now];
            for(int k=1;k<=n;k++)
                a[j][k]-=a[now][k]*x;
        }
        ++now;
    }
    double ans=1;
    for(int i=1;i<=n;i++)
        ans*=a[i][i];
    printf("%.lf\n",fabs(ans));
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        memset(A,0,sizeof(A));
        memset(B,0,sizeof(B));
        scanf("%d%d",&n,&m);
        n--;
        while(m--){
            int u,v;
            scanf("%d%d",&u,&v);
            u--;v--;
            A[u][u]++;A[v][v]++;
            B[u][v]++;B[v][u]++;
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                a[i][j]=A[i][j]-B[i][j];
        gauss();
    }
    return 0;
}
时间: 2024-08-05 14:51:38

[spoj104][Highways] (生成树计数+矩阵树定理+高斯消元)的相关文章

P3317 [SDOI2014]重建 变元矩阵树定理 高斯消元

传送门:https://www.luogu.org/problemnew/show/P3317 这道题的推导公式还是比较好理解的,但是由于这个矩阵是小数的,要注意高斯消元方法的使用: #include <algorithm> #include <iterator> #include <iostream> #include <cstring> #include <cstdlib> #include <iomanip> #include

BZOJ 2466 [中山市选2009]树(高斯消元)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2466 [题目大意] 给定一棵树,每个节点有一盏指示灯和一个按钮.如果节点的按扭被按了, 那么该节点的灯会从熄灭变为点亮(当按之前是熄灭的),或者从点亮到熄灭 并且该节点的直接邻居也发生同样的变化.开始的时候,所有的指示灯都是熄灭的. 请编程计算最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态. [题解] 高斯消元枚举自由变元回代. [代码] #include <cstdio>

再探矩阵树定理

坚定不移的向前奔跑 才是我应该做的事情吧. 多思考一下 你会发现不一样的世界. 所谓矩阵树定理 用于一张无向图之上求出该图的所有生成树的个数. 在探究其之前我们先再次回顾一番 矩阵的基本定义 和一些比较基本的操作. 矩阵 有行有列 不过有两个定义 行向量 和 列向量 分别指某一行或某一列所形成的向量.(高维空间 线性空间 对于一个向量 w 如果w可以表示为 \(w=\sum_{v_i\in S}a_iv_i\) 那么我们认为w是可以被S中的向量线性组合出来的. 线性无关:如果一个向量空间中的每个

线性空间和异或空间(线性基)bzoj4004贪心+高斯消元

线性空间:是由一组基底构成的所有可以组成的向量空间 对于一个n*m的矩阵,高斯消元后的i个主元可以构成i维的线性空间,i就是矩阵的秩 并且这i个主元线性无关 /* 每个向量有权值,求最小权极大线性无关组 本题是使用贪心策略的高斯消元 由输入给出的n个物品,每个物品有m种属性,和价格price 如果a物品的属性可以由其他已有物品的属性组合出,那么a可以不必购买 问最少花掉多少钱,使得所有物品都可以组合出 首先构建n*m矩阵,然后高斯消元 在求第i个主元时,取价格最小的那个即可 可用反证法证明 */

spoj104 HIGH - Highways 矩阵树定理

欲学矩阵树定理必先自宫学习一些行列式的姿势 然后做一道例题 #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; typedef long long ll; int T, n, m, uu, vv; double w[15][15]; const double eps=1e-7; void gauss(){ n--; for

【bzoj2467】[中山市选2010]生成树 矩阵树定理

题目描述 有一种图形叫做五角形圈.一个五角形圈的中心有1个由n个顶点和n条边组成的圈.在中心的这个n边圈的每一条边同时也是某一个五角形的一条边,一共有n个不同的五角形.这些五角形只在五角形圈的中心的圈上有公共的顶点.如图0所示是一个4-五角形圈. 现在给定一个n五角形圈,你的任务就是求出n五角形圈的不同生成树的数目.还记得什么是图的生成树吗?一个图的生成树是保留原图的所有顶点以及顶点的数目减去一这么多条边,从而生成的一棵树. 注意:在给定的n五角形圈中所有顶点均视为不同的顶点. 输入 输入包含多

【Luogu】P3317重建(高斯消元+矩阵树定理)

题目链接 因为这个专门跑去学了矩阵树定理和高斯消元qwq 不过不是很懂.所以这里只放题解 玫葵之蝶的题解 某未知dalao的矩阵树定理 代码 #include<cstdio> #include<cstdlib> #include<cctype> #include<algorithm> #include<cstring> #include<cmath> #define eps 1e-8 #define maxn 100 using na

hdu4305Lightning 生成树计数(基尔霍夫矩阵)+高斯消元+逆元

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4305 题意:比较裸的生成树计数问题. 如何处理生成树计数问题? 基尔霍夫矩阵: if i==j  Kir[i][j] = i的度数 if i!=j   Kir[i][j] = i到j的平行边的个数的负数 即,基尔霍夫矩阵 = 度数矩阵 - 邻接矩阵 将基尔霍夫矩阵删去第i行和第i列,余下i-1阶的行列式的值即为生成树个数.(证明略) 求行列式的值可以将行列式转为上三角阵,求对角线上的积即为行列式的值.

【算法】Matrix - Tree 矩阵树定理 &amp; 题目总结

最近集中学习了一下矩阵树定理,自己其实还是没有太明白原理(证明)类的东西,但想在这里总结一下应用中的一些细节,矩阵树定理的一些引申等等. 首先,矩阵树定理用于求解一个图上的生成树个数.实现方式是:\(A\)为邻接矩阵,\(D\)为度数矩阵,则基尔霍夫(Kirchhoff)矩阵即为:\(K = D - A\).具体实现中,记 \(a\) 为Kirchhoff矩阵,则若存在 \(E(u, v)\) ,则\(a[u][u] ++, a[v][v] ++, a[u][v] --, a[v][u] --\