模板題點這
題目大意:
*一個有n座城市的組成國家,城市1至n編號,其中一些城市之間可以修建高速公路;
*需要有選擇的修建一些高速公路,從而組成一個交通網(wǎng)絡;
*計算有多少種方案,使得任意兩座城市之間恰好只有一條路徑;
模板 :
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=20;
int degree[maxn]; //度數(shù)矩陣,記錄每一個點的度數(shù). //不懂就看下上面那個定理證明.
ll a[maxn][maxn]; //矩陣樹, 對角線是度數(shù)矩陣的每一個數(shù),其余地方為 a[i][j] = a[i][j] - vis[i][j] ;
int vis[maxn][maxn]; //臨接矩陣,u與v相連就是等于1,否則就是為0.注意是無向邊.
ll det(int n) //生成樹計數(shù):Matrix-Tree定理 //這個是求行列式的精華啊(實質(zhì)上這個子函數(shù)就是用來求行列式的值的!)(所以也適用于求行列式值的題)
{
ll ret=1;
for(int i=2; i<=n; i++) //計算任意一個n-1階行列式的值就是答案.
{
for(int j=i+1; j<=n; j++){
while(a[j][i])
{
ll t=a[i][i]/a[j][i]; //如果要模,則這里就一下
for(int k=i; k<=n; k++)
a[i][k]=(a[i][k]-a[j][k]*t); //加一下
for(int k=i; k<=n; k++)
swap(a[i][k],a[j][k]);
ret=-ret;
}
}
if(a[i][i]==0)
return 0; //圖無法聯(lián)通.
ret*=a[i][i]; //加一下
}
if(ret<0) // 可以縮合為 ((ret % p ) + p ) % p ;
ret=-ret;
return ret;
} //這個就是程序的主要函數(shù),計算行列式的值.
int main()
{
int tcase;
scanf("%d",&tcase);
while(tcase--)
{
memset(degree,0,sizeof(degree));
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
int n,m;
scanf("%d%d",&n,&m);
int u,v;
while(m--)
{
scanf("%d%d",&u,&v);
vis[u][v]=1; //相連就是1,否則就是0.
vis[v][u]=1;
degree[u]++;
degree[v]++;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) a[i][j] = degree[i];
else a[i][j] -= vis[i][j];
}
}
printf("%lld\n",det(n));
}
return 0;
}
綜合一下,還可以這樣寫:
(這個是在定理上面加強版,把一些步驟直接在縮合在了一起)
靈活點就是在目標矩陣中,為:(對于一些變形題就這樣處理).
無向圖的基爾霍夫矩陣: 對角線上表示每個點的度數(shù),若ij之間有邊則矩陣ij處為-1
無向圖的生成樹的數(shù)目為: 任意一個n-1階主子式的行列式的絕對值.
while(m--)
{
scanf("%d%d",&u,&v);
a[u][v]=a[v][u]=-1; //u與v相連,所以在目標矩陣中為-1.
degree[u]++;
degree[v]++;
}
for(int i=1;i<=n;i++)
a[i][i]=degree[i];