1. 程式人生 > >P2144 [FJOI2007]輪狀病毒

P2144 [FJOI2007]輪狀病毒

orz 神奇 OS view event alt math AI pic

P2144 [FJOI2007]輪狀病毒

題目描述

輪狀病毒有很多變種。許多輪狀病毒都是由一個輪狀基產生。一個n輪狀基由圓環上n個不同的基原子和圓心的一個核原子構成。2個原子之間的邊表示這2個原子之間的信息通道,如圖1。

n輪狀病毒的產生規律是在n輪狀基中刪除若幹邊,使各原子之間有唯一一條信息通道。例如,共有16個不同的3輪狀病毒,入圖2所示。

給定n(N<=100),編程計算有多少個不同的n輪狀病毒。

技術分享圖片

輸入輸出格式

輸入格式:

第一行有1個正整數n。

輸出格式:

將編程計算出的不同的n輪狀病毒數輸出

輸入輸出樣例

輸入樣例#1: 復制
3
輸出樣例#1: 復制
16

分析

首先想到的是生成樹計數,數據範圍也剛剛好,然後不過QAQ。

在網上看到大神一個神奇的式子: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

P2144 [FJOI2007]輪狀病毒