[SP104 HIGH]Highways [HEOI2015]小Z的房間——矩陣樹定理入門
阿新 • • 發佈:2018-12-13
矩陣樹定理:
用於計算無向連通圖的生成樹個數。 計算出整張圖的度數矩陣D(即表示i的度數),和鄰接矩陣A(即表示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;
}