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;
}

 标算就不放上来了,反正就没几行。

posted @ 2017-12-15 20:48  泪寒之雪  阅读(220)  评论(0编辑  收藏  举报