On matrix Tree Theorem (Kirchhoff || Laplace) --Part 1 (undirected graph count)

Prerequisite knowledge:

  Gaussian elimination, graph theory basics (like on this ... (fog))


 

 

Here is part of undirected graph, please do the wrong field. . .

definition

  We will adjacency matrix is ​​defined as the matrix A (u, v), I think the adjacency matrix would not say any more;

  We will define the degree matrix for each point matrix D (u, v), where together with the mathematical representation;

  D (u, u) = u degree that point, D (u, v) = 0 (u = v!);

  We LAPLACE matrix (or of Kirchhoff) is defined as L (u, v) = D (u, v) -A (u, v)

  We'll MST is defined as the number of t;

Introduced

  Here determinant will tell if dalao have learned, you can skip this part directly;

  Incorporated herein determinant is N * N matrix (because the adjacency matrix is ​​a square), e.g.

  

  Determinant formula is

      

  PS: wherein v is l1, l2, l3 ... ln the reverse order number;

  Determinant has several properties:

  •   Trekking exchange, the opposite result;
  •   Trekking overlay, the same result;
  •   Elongation ratio of matrix rows, like the increase;

  PS:

  A simple proof of the nature of 1:

    Determinant understood from the formula, trekking exchange, the inevitable changes in reverse order, a change, then the time will change the resulting symbol;

  Nature 2 added:

    Can let other rows by k superimposed on this line, the same result;

  Based on these, we can find, Gaussian elimination can be a good use of these properties, then the Gaussian elimination is the diagonal matrix multiplication results;

  I hired a matrix L is optimized to prove, to be honest from another location, I was a little Mongolia

  

  With this property we can count less a line, which should be considered to optimize it (guilty conscience ~

application

  Such thinking will be very clear, here is the determinant of the matrix L number of spanning tree, then we have the steps of:

  1. First matrix configuration L, according to the equation L = D - A, we can easily obtain a matrix L, of course, can be directly operated upon reading side, such as side u -> v, we wish to make f [u] [ v] = f [v] [u] - -, f [u] [u] ++, f [v] [v] ++.
  2. Then the matrix Gaussian elimination, and calculates the product of the diagonal.
  3. Because sometimes must be an integer, we can use the minus phase division method is similar to flounder, detailed below.

model

  Template Title: Small Z's room

  Clear, as long as the building side and up and down about a point, construction of matrix L, is solved by Gaussian elimination;

  However, seeking the general Gaussian elimination decimal form, this is not ideal because it is the program number (decimal impossible ah QWQ);

  Application of the method here is similar to the division removed, review removed division, MOD taking two numbers, then the exchange position until a date is 0;

  Gaussian elimination also eliminate the other number is 0, then we change it to function, as follows (see Note):

LL GAUSS () { 
    LL ANS = 1 ; n-= cent- 1 ; // use a theorem, cent of the total number of points 
    for ( int I = 1 ; I <= n-; I ++ ) {
         for ( int J = I + 1 ; J <= n-; J ++ ) {
             the while (F [J] [I]) { // class Euclidean until a is 0 
                int T = F [I] [I] / F [J] [I];
                 / / note is of type int (rounded down), not less complete, but the Save F [I] [I] <F [J] [I] 
                for ( int K = I; K <= n-; K ++ ) 
                    F [ I] [K] = (F [I] [K] -f [J] [K] + MOD MOD *% T)% MOD;
                the swap (F [I], F [J]); // exchange position Save removed 
                 // exchange position is mentioned above as F [I] [I] <F [J] [I] 
                ANS = -ans; / / exchange position trans to take 
            } 
        } 
        ANS = (ANS * F [I] [I] + MOD)% MOD; 
    } 
    return ANS; 
}

  It should be fairly clear explanation of similar complexity of division removed about one more logn, the total complexity of O (n3logn) I would put the entire code here, we considered a template:

#include <bits / STDC ++ H.>
 #define LL Long Long
 #define MOD 1000000000
 the using  namespace STD;
 int n-, m, A [ 100 ] [ 100 ], Cent; 
LL F [ 100 ] [ 100 ]; 

inline void the Add ( int U, int V) { 
    F [U] [U] ++, F [U] [V] - ; 
} // Since the matrix symmetry, so subtraction just once. . . 

GAUSS LL () { 
    LL ANS = 1 ; n-cent- = 1 ; // Theorem 1, cent of the total number of points 
    for ( int I =. 1 ; I <= n-; I ++ ) {
         for ( int J = I + . 1 ; J <= n-; J ++ ) {
             the while (F [J] [I]) { // class Euclidean until a is 0 
                int T F = [I] [I] / F [J] [I];
                 // note is of type int (rounded down), not less complete, but the Save f [i] [i] < f [j] [ I] 
                for ( int K = I; K <= n-; K ++ ) 
                    F [I] [K] = (F [I] [K] -f [J] [K] * T% MOD + MOD)% MOD; 
                the swap (F [I], F [J]); // exchange position Save removed 
                 // exchange position is mentioned above as F [I] [I] <F [J] [I] 
                ANS = -ans; / / exchange position trans to take 
            } 
        }
        ans=(ans*f[i][i]+mod)%mod;
    }
    return ans;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            char s=getchar();
            while(s!='.'&&s!='*')
                s=getchar();//防止输入出错 
            if(s=='.') a[i][j]=++cent;//命名 
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            int now,rou;
            if(!(now=a[i][j])) continue;
            if(rou=a[i-1][j]) add(now,rou);
            if(rou=a[i][j-1]) add(now,rou);
            if(rou=a[i+1] [J]) the Add (now, ROU);
            if (ROU = A [I] [J + . 1 ]) the Add (now, ROU); // Construction L matrix 
        } 
    the printf ( " % LLD \ n- " , (GAUSS () MOD +) MOD%); // can not be negative. . . 
}

Thorough

  Understand the template of course, is not enough, we should experience some tips:

  [SDOI2014] reconstruction

  The subject is no longer attached, we direct narrative;

  Here too is the number of spanning tree, but the difference is that here the right side has a value, but out of the way and here, we will describe how a little weight to deal with.

  According to the basic high school knowledge of probability, there is no intersection of two events A, B, respectively, the probability P (A), P (B), then P (AB) = P (A) * P (B), this should know everything .

  Then the probability of each side link is P (u, v), then the probability is not communicating 1-P (u, v), this should be apparent.

  Then the probability of a spanning tree P (G) = Π P (u, v) * (1 - P (x, y), wherein the edge u, v belongs spanning G, and x, y does not belong to this edge.

  So, Σ P (G) is the total probability, we will transform the equation. (I will not formula markdown, so I can not argue, if they feel uncomfortable can own hands to push directly see the results)

  (Note: Σ is the sum, Π for the sake of product)

  Σ Π P (u, v) * (1-P (x, y)) = Σ Π P (u, v) * (1-P (G)) / P (u, v) = Σ (1 - P (G)) Π P (u, v) / (1-P (u, v);

  Explain, because the tree belong to the G side and complement each other side of the tree does not belong to G, so you can take advantage of this nature, I direct expression of this formula

  

sum = sigma (1-P(G)) Π(P[u][v]/(1-P[u][v]));

  This is very evident when the P [U] [V] / ( . 1-P [U] [V] as the edge weight value, but how to handle the right side, here the steps of:

  1. We read in the matrix, to redefine the edge weights;

  2. The degree of edge weights as applied on a diagonal line, then as the number of sides of the adjacency matrix can be subtracted;

  3. Gaussian elimination;

  Introductions, Code:

#include<bits/stdc++.h>
#define maxn 57
#define db double
using namespace std;
int n;
db f[maxn][maxn],ans=1.0;
const db eps=1e-8;

db Gauss(){
    n--;db ol=1.0;
    for(int i=1;i<=n;i++){
        int sp=i;
        for(int j=i+1;j<=n;j++)
            if(fabs(f[j][i])>fabs(f[sp][i])) sp=j;
        IF (! I = SP) the swap (F [I], F [SP]), ANS = - ANS;
         for ( int J = I + . 1 ; J <= n-; J ++ ) { 
            DB T = F [J] [I ] / F [I] [I];
             for ( int K = I; K <= n-; K ++ ) 
                F [J] [K] - = F [I] [K] * T; 
        } 
        OL * = F [I ] [I]; 
    } 
    return OL; 
} // this is the decimal, so the operation will not so Kichiku. . 

// SUM = Sigma P (G) [pi (P [U] [V] / (. 1-P [U] [V])); 

int main () { 
    Scanf ( " % D " , & n-);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%lf",&f[i][j]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            db t=max((1.0-f[i][j]),eps);//小心 0 哦 
            if(i>j) ans*=t;//累加,得出 1-P(G) 
            f[i][j]/=t;//步骤1 
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j){
                f[i][i]+=f[i][j]; 
                f[i][j]=-f[i][j];
            }//步骤2 ,构图 
    printf("%.10lf",fabs(Gauss()*ans));
}

  [SHOI2016] before dark fantasy Township

  Here used inclusion and exclusion, and other binary enumeration techniques, inclusion and exclusion I will not describe, it will not be yy at (escape ~

  Directly on the code (there is conscience comment)

#include<bits/stdc++.h>
#define maxn 19
#define ll long long
#define mod 1000000007
using namespace std;
int n,m;
vector<pair<int ,int > >a[maxn];
ll f[maxn][maxn],ans;

ll Gauss(){
    int m=n-1;ll ol=1;
    for(int i=1;i<=m;i++){
        for(int j=i+1;j<=m;j++){
            while(f[j][i]){
                int t=f[i][i]/f[j][i];
                for(int k=i;k<=m;k++)
                    f[i][k]=(f[i][k]-f[j][k]*t%mod+mod)%mod;
                swap(f[i],f[j]);ol=-ol;
            }
        }
        ol=ol*f[i][i]%mod;
    }
    return (ol+mod)%mod;
}//唉,方案数。。。 

void add(int u,int v){
    f[u][u]++,f[v][v]++;
    f[u][v]--,f[v][u]--;
}

int main(){
    scanf("%d",&n);
    for(int i=1,t,u,v;i<=n-1;i++){
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&u,&v);
            a[i].push_back(make_pair(u,v));//存图 
        }
    }
    int lim=1<<(n-1);
    for(int i=1;i<lim;i++){
        int cnt=0;memset(f,0,sizeof(f));//暴力建图 
        for(int k=0;k<n-1;k++){//二进制枚举 
            if((1<<k)&i){
                cnt++;
                for(int j=0;j<a[k+1].size();j++)
                    add(a[k+1][j].first,a[k+1][j].second);
            } 
        }
        IF ((n--CNT) & . 1 ) ANS = (ANS + GAUSS ())% MOD;
         // inclusion and exclusion. . . In fact, odd and even, respectively, addition and subtraction. . . 
        the else ANS = (ANS-GAUSS () + MOD) MOD%; // prevent negative. . . 
    } 
    The printf ( " % LLD \ n- " , ANS); 
}

to sum up

  In fact, there are some content, but due to catch a review, no speak.

  We did this a few questions, nothing more than to build charts, statistical answers, set a checkpoint when Gaussian elimination, resulting in difficulty jump title.

  But since it already knows where to test, I wanted to go out into the place which, like the topic of training, and then find out the characteristics to find the shadow of this algorithm in the comprehensive title;

  The main feature of this algorithm is counting spanning tree, so it should be good to see it, to remember the characteristics and processing methods, and foster mathematical thinking is made subject;

Guess you like

Origin www.cnblogs.com/waterflower/p/11300113.html