P2144 [FJOI2007]轮状病毒

P2144 [FJOI2007]轮状病毒

题目描述

轮状病毒有很多变种。许多轮状病毒都是由一个轮状基产生。一个n轮状基由圆环上n个不同的基原子和圆心的一个核原子构成。2个原子之间的边表示这2个原子之间的信息通道,如图1。

n轮状病毒的产生规律是在n轮状基中删除若干边,使各原子之间有唯一一条信息通道。例如,共有16个不同的3轮状病毒,入图2所示。

给定n(N<=100),编程计算有多少个不同的n轮状病毒。

输入输出格式

输入格式:

 

第一行有1个正整数n。

 

输出格式:

 

将编程计算出的不同的n轮状病毒数输出

 

输入输出样例

输入样例#1: 复制
3
输出样例#1: 复制
16

分析

首先想到的是生成树计数,数据范围也刚刚好,然后不过。

在网上看到大神一个神奇的式子: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])  
View Code

 

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 }
View Code

 

posted @ 2018-03-10 11:24  MJT12044  阅读(246)  评论(0编辑  收藏  举报