BZOJ 1002 [FJOI2007]轮状病毒
轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个N轮状基由圆环上N个不同的基原子
和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示
N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不
同的3轮状病毒,如下图所示
现给定n(N<=100),编程计算有多少个不同的n轮状病毒
SOL:
本来看到生成树计数,脑子一热,打了一个拉普拉斯算子求矩阵行列式,打完发现long double炸精度,然后调了很久的高精度,高精度的行列式真心难写,最后放弃治疗。但是,我们发现这张图的边是有规律的。我们可以打表发现,Fn=3Fn-1-Fn-2+2。
这是炸精度的拉普拉斯算子:
#include<bits/stdc++.h> #define gc getchar #define sight(c) ('0'<=c&&c<='9') //#define getchar nc #define double long double #define bug 1000007 #define SIZ 107 #define fabs(x) ((x)>0?(x):(-x)) #define zero(x) (fabs(x)>1e-9?0:1) using namespace std; int n; int f[SIZ][SIZ]; double b[SIZ][SIZ]; inline char nc () { static char buf[bug],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,bug,stdin),p1==p2)?EOF:*p1++; } inline void read(int &x){ static char c;static int b; for(c=gc(),b=1;!sight(c);c=gc()) c=='-'?b=-1:b; for(x=0;sight(c);x=x*10+c-48,c=gc()); x*=b; } double det() { double ret = 1;int sign=0; for (int i=0;i<n;i++) for (int j=0;j<n;j++) b[i][j]=f[i][j]; for (int i=0,j,k;i<n;i++) { if (zero(b[i][i])) { for (j=i+1;j<n;j++) if (!zero(b[j][i])) break; if (j == n) return 0; for (k=i;k<n;k++) swap(b[i][k],b[j][k]); sign++; } ret*= b[i][i]; for (k = i + 1; k < n; k++) b[i][k] /= b[i][i]; for (j = i + 1; j < n; j++) for (k = i + 1; k < n; k++) b[j][k] -= b[j][i] * b[i][k]; } if (sign & 1) ret = -ret; return ret; } int main () { // freopen("a.in","r",stdin); read(n); for (int i=0;i<n;i++) { f[i][i]=3; f[i][(i+1)%n]--; f[i][(i+n-1)%n]--; } printf("%.0Lf\n",det()); return 0; }
标算就不放上来了,反正就没几行。