P2144 [FJOI2007]轮状病毒
P2144 [FJOI2007]轮状病毒
题目描述
轮状病毒有很多变种。许多轮状病毒都是由一个轮状基产生。一个n轮状基由圆环上n个不同的基原子和圆心的一个核原子构成。2个原子之间的边表示这2个原子之间的信息通道,如图1。
n轮状病毒的产生规律是在n轮状基中删除若干边,使各原子之间有唯一一条信息通道。例如,共有16个不同的3轮状病毒,入图2所示。
给定n(N<=100),编程计算有多少个不同的n轮状病毒。
输入输出格式
输入格式:
第一行有1个正整数n。
输出格式:
将编程计算出的不同的n轮状病毒数输出
输入输出样例
分析
首先想到的是生成树计数,数据范围也刚刚好,然后不过。
在网上看到大神一个神奇的式子:F(n)为n轮状病毒的个数,F(n) = 3F(n - 1) - F(n - 2) + 2
也可以搜索,打表,找规律。。。orz
不过需要高精度。。于是找到了一个Python代码。
code
python
1 n=int(raw_input()) 2 f=[0]*105 3 f[1]=1 4 for i in range(2,101): 5 f[i]=3*f[i-1]-f[i-2]+2 6 print(f[n])
40分Matrix-tree定理求生成树计数。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 6 using namespace std; 7 const double eps = 1e-12; 8 double c[110][110],ans; 9 int n; 10 11 void build() { 12 int M = n+1; 13 for (int i=1; i<n; ++i) c[i][i+1] = c[i+1][i] = -1; 14 c[n][1] = c[1][n] = -1; 15 for (int i=1; i<=n; ++i) { 16 c[i][i] = 3; 17 c[i][M] = c[M][i] = -1; 18 } 19 c[M][M] = n; 20 } 21 void Gauss() { 22 for (int k=1; k<=n; ++k) { 23 int r = k; 24 for (int i=k+1; i<=n; ++i) 25 if (fabs(c[i][k]) > fabs(c[r][k])) r = i; 26 if (r != k) for (int j=1; j<=n; ++j) swap(c[r][j],c[k][j]); 27 for (int i=k+1; i<=n; ++i) 28 if (fabs(c[i][k]) > eps) { 29 double t = c[i][k] / c[k][k]; 30 for (int j=k; j<=n; ++j) c[i][j] -= t*c[k][j]; 31 } 32 } 33 ans = 1.0; 34 for (int i=1; i<=n; ++i) ans *= c[i][i]; 35 ans = ans<0?-ans:ans; 36 } 37 int main() { 38 scanf("%d",&n); 39 build(); 40 Gauss(); 41 printf("%.0lf\n",ans+eps); 42 return 0; 43 }