1. 程式人生 > >[SP104 HIGH]Highways [HEOI2015]小Z的房間——矩陣樹定理入門

[SP104 HIGH]Highways [HEOI2015]小Z的房間——矩陣樹定理入門

矩陣樹定理:

用於計算無向連通圖的生成樹個數。 計算出整張圖的度數矩陣D(即Di,iD_{i,i}表示i的度數),和鄰接矩陣A(即Ai,jA_{i,j}表示i和j的連邊的數量),然後得到基爾霍夫矩陣(D-A),計算新矩陣的任意n-1階主子式的絕對值即可。

計算行列式的值:

行列式的值直接計算複雜度太高,於是我們利用類似於高斯消元的方法將行列式消成一個上三角矩陣,不難得出此時除了主對角線之外,行列式值中的其它項為0,於是直接計算主對角線的乘積即可。 由於是行列式的變換,所以每交換一次都要注意答案符號的變化。題目可能要求取模,高斯消元時取模計算不太方便,可以行與行之間輾轉相除即可。

題目:

// luogu-judger-enable-o2
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("bzoj4031.in","r",stdin);
    freopen("bzoj4031.out","w",stdout);
}

template<typename T>void read(T &
_){ T __=0,mul=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')mul=-1; ch=getchar(); } while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar(); _=__*mul; } const ll mod=1e9; const int maxn=15; const int maxs=210; int n,m,num[maxn][maxn],tot; int
dx[3]={0,1,0}; int dy[3]={0,0,1}; ll D[maxs][maxs],A[maxs][maxs],a[maxs][maxs],ans=1; char s[maxn][maxn]; bool judge(int x,int y){return x>=1 && x<=n && y>=1 && y<=m && s[x][y]!='*';} void init(){ read(n); read(m); REP(i,1,n)scanf("%s",s[i]+1); REP(i,1,n)REP(j,1,m)if(s[i][j]=='.') num[i][j]=++tot; REP(i,1,n)REP(j,1,m)if(s[i][j]=='.'){ REP(k,1,2){ int nx=i+dx[k],ny=j+dy[k]; if(!judge(nx,ny))continue; int num1=num[i][j],num2=num[nx][ny]; ++D[num1][num1]; ++D[num2][num2]; A[num1][num2]=A[num2][num1]=1; } } REP(i,1,tot)REP(j,1,tot)a[i][j]=D[i][j]-A[i][j]; } void print(){ REP(i,1,tot)cout<<"---"; cout<<endl; REP(i,1,tot){ REP(j,1,tot)cout<<a[i][j]<<" "; cout<<endl; } REP(i,1,tot)cout<<"---"; cout<<endl; } void work(){ --tot; REP(i,1,tot){ REP(j,i+1,tot){ while(a[j][i]){ ll t=a[i][i]/a[j][i]; REP(k,i,tot)a[i][k]=(a[i][k]-t*a[j][k])%mod,swap(a[i][k],a[j][k]); ans*=-1; } } ans=ans*a[i][i]%mod; } printf("%lld\n",(ans+mod)%mod); } int main(){ // File(); init(); work(); return 0; }
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
typedef long long ll;

using namespace std;

void File(){
    freopen("spoj104.in","r",stdin);
    freopen("spoj104.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=12+10;
int T,n,m;
ll D[maxn][maxn],A[maxn][maxn],a[maxn][maxn],ans;

int main(){
//	File();
    read(T);
    while(T--){
        ans=1;
        memset(D,0,sizeof(D));
        memset(A,0,sizeof(A));
        memset(a,0,sizeof(a));
        read(n); read(m);
        int u,v;
        REP(i,1,m){
            read(u); read(v);
            ++D[u][u]; ++D[v][v];
            A[u][v]=A[v][u]=1;
        }
        REP(i,1,n)REP(j,1,n)a[i][j]=D[i][j]-A[i][j];
        --n;
        REP(i,1,n)REP(j,i+1,n)while(a[j][i]){
            ll t=a[i][i]/a[j][i];
            REP(k,i,n)a[i][k]-=t*a[j][k],swap(a[i][k],a[j][k]);
        }
        REP(i,1,n)ans*=a[i][i];
        printf("%lld\n",abs(ans));
    }
    return 0;
}