题意简述
求一种特殊无向图的生成树个数
无向图如图:
题解思路
用Matrix-Tree定理,求出基尔霍夫矩阵来计算,再递推答案;
(Ans(x)=3 imes Ans(x-1)-Ans(x-2)+2)
证明:
我们令轮状病毒圆心编号为1,圆环上点编号从2~n+1
则可以得出无向图的度数矩阵D和邻接矩阵E
(D=egin{bmatrix}n&0&0&0&0&cdots&0&0&0&0\0&3&0&0&0&cdots&0&0&0&0\0&0&3&0&0&cdots&0&0&0&0\0&0&0&3&0&cdots&0&0&0&0\0&0&0&0&3&cdots&0&0&0&0\vdots&vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\0&0&0&0&0&cdots&3&0&0&0\0&0&0&0&0&cdots&0&3&0&0\0&0&0&0&0&cdots&0&0&3&0\0&0&0&0&0&cdots&0&0&0&3\end{bmatrix})
(E=egin{bmatrix}0&1&1&1&1&cdots&1&1&1&1\1&0&1&0&0&cdots&0&0&0&1\1&1&0&1&0&cdots&0&0&0&0\1&0&1&0&1&cdots&0&0&0&0\1&0&0&1&0&cdots&0&0&0&0\vdots&vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\1&0&0&0&0&cdots&0&1&0&0\1&0&0&0&0&cdots&1&0&1&0\1&0&0&0&0&cdots&0&1&0&1\1&1&0&0&0&cdots&0&0&1&0\end{bmatrix})
再得到
基尔霍夫Kirchhoff矩阵 (K=egin{bmatrix}n&-1&-1&-1&-1&cdots&-1&-1&-1&-1\-1&3&-1&0&0&cdots&0&0&0&-1\-1&-1&3&-1&0&cdots&0&0&0&0\-1&0&-1&3&-1&cdots&0&0&0&0\-1&0&0&-1&3&cdots&0&0&0&0\vdots&vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\-1&0&0&0&0&cdots&3&-1&0&0\-1&0&0&0&0&cdots&-1&3&-1&0\-1&0&0&0&0&cdots&0&-1&3&-1\-1&-1&0&0&0&cdots&0&0&-1&3\end{bmatrix})
然后我们要求K的代数余子式的值,显然是将带有n的那一行,那一列(即第一行,第一列)去掉
接下来就是求n阶行列式(A=egin{vmatrix}3&-1&0&0&cdots&0&0&0&-1\-1&3&-1&0&cdots&0&0&0&0\0&-1&3&-1&cdots&0&0&0&0\0&0&-1&3&cdots&0&0&0&0\vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\0&0&0&0&cdots&3&-1&0&0\0&0&0&0&cdots&-1&3&-1&0\0&0&0&0&cdots&0&-1&3&-1\-1&0&0&0&cdots&0&0&-1&3\end{vmatrix})
对于A,显然不能用(n^3)的高斯消元,所以我们要探究A的性质。
将A的第一行变换到最后一行,得到(B=egin{vmatrix}-1&3&-1&0&cdots&0&0&0&0\0&-1&3&-1&cdots&0&0&0&0\0&0&-1&3&cdots&0&0&0&0\0&0&0&-1&cdots&0&0&0&0\vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\0&0&0&0&cdots&-1&3&-1&0\0&0&0&0&cdots&0&-1&3&-1\-1&0&0&0&cdots&0&0&-1&3\3&-1&0&0&cdots&0&0&0&-1\end{vmatrix})
先根据行列式的性质得到(A=(-1)^{n-1} imes B)
我们发现除了左下角有三个数字外,B已经是一个上三角行列式,接下来是要消去左下角的三个数字
先消第n-1行(倒数第二行)
假设现在在消第i位,设(F_i)表示这一行的第i个数,(G_i)表示这一行第i+1个数
那么我们可以将B的第i行( imes F_i)加到这一来,就可消去第i位。因为第i行-1后面一定是3,所以第i+1位(+3 imes F_i)同理,第i+2位(+(-F_i))。
即
(egin{cases}F_{i+1}=G_i+3 imes F_i\G_{i+1}=-F_i\end{cases})
由第二个式子推出(G_i=-F_{i-1})带人第一个式子中,得到(F_{i+1}=3 imes F_i-F_{i-1}),同时也可得到(G_{i+1}=3 imes G_i-G_{i-1})
然后可以快速地将第n-1行消成(egin{bmatrix}0&0&0&0&cdots&0&0&F_{n-1}-1&G_{n-1}+3end{bmatrix}) 了
同样的方法,我们可以来消第n行
设第i位为(H_i),第i+1位为(L_i)
可得方程
(egin{cases}H_{i+1}=L_i+3 imes H_i\L_{i+1}=-H_i\end{cases})
解得(H_{i+1}=3 imes H_i-H_{i-1}qquad L_{i+1}=3 imes L_i-L_{i-1})
将第n行消成(egin{bmatrix}0&0&0&0&cdots&0&0&H_{n-1}&L_{n-1}-1end{bmatrix})
设(F_{n-1}-1=fqquad G_{n-1}+3=gqquad H_{n-1}=hqquad L_{n-1}-1=l;)
则(B=egin{vmatrix}-1&3&-1&0&cdots&0&0&0&0\0&-1&3&-1&cdots&0&0&0&0\0&0&-1&3&cdots&0&0&0&0\0&0&0&-1&cdots&0&0&0&0\vdots&vdots&vdots&vdots&ddots&vdots&vdots&vdots&vdots\0&0&0&0&cdots&-1&3&-1&0\0&0&0&0&cdots&0&-1&3&-1\0&0&0&0&cdots&0&0&f&g\0&0&0&0&cdots&0&0&h&l\end{vmatrix})=((-1)^{n-2} imes egin{vmatrix}f&g\h&l\end{vmatrix})
所以(A=(-1)^{n-1} imes B=(-1)^{2n-3} imes egin{vmatrix}f&g\h&l\end{vmatrix}=-f imes l+g imes h)
再推一推F,G,H,L,可以看出
(H_{i-1}=L_{i}=F_{i}=G_{i+1})
最后就可以推出(Ans(n)=3 imes Ans(n-1)-Ans(n-2)+2)了
如果推不出,也可以求出(F_{i-1},F_{i},F_{i+1})再来求答案
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
int n;
struct Number {
int len;
int num[1000];
Number() {
len=0;
memset(num,0,sizeof(num));
}
void operator =(const Number x) {
len=x.len;
for (register int i=1;i<=len;++i) num[i]=x.num[i];
}
void operator +=(const Number x) {
len=std::max(len,x.len);
for (register int i=1;i<=len;++i) {
num[i]=num[i]+x.num[i];
if (num[i]>=10) num[i]-=10,++num[i+1];
}
if (num[len+1]) ++len;
}
void operator -=(const Number x) {
int xx=std::min(len,x.len);
for (register int i=1;i<=xx;++i) {
num[i]=num[i]-x.num[i];
if (num[i]<0) num[i]+=10,--num[i+1];
}
while (!num[len]) --len;
}
Number operator *(const int& x) {
Number res;
for (register int i=1;i<=len;++i) {
res.num[i]+=num[i]*3;
res.num[i+1]+=res.num[i]/10;
res.num[i]=res.num[i]%10;
}
res.len=len;
if (res.num[len+1]) ++res.len;
return res;
}
void print() {
for (register int i=len;i;--i) printf("%d",num[i]);
puts("");
}
} x,y,z,_2;
int main() {
scanf("%d",&n);
if (n==1) puts("1");
else if (n==2) puts("5");
else {
_2.len=1; _2.num[1]=2;
x.len=x.num[1]=1;
y.len=1; y.num[1]=5;
for (register int i=3;i<=n;++i) {
z=y*3; z-=x; z+=_2;
x=y; y=z;
}
z.print();
}
}