您的位置:首页 > 其它

BZOJ 1002 轮状病毒

2015-12-17 13:58 316 查看
这是很久前看到的题了,一直不知如何下手,有一段时间误解了。直到前天决定对这道题下手了。去百度了一下,有人说是和基尔霍夫矩阵有关,也有人曾说和卢卡斯数列有关。

一开始看了基尔霍夫矩阵,真的是一脸茫然,这是怎么解决这道题的呢!后来仔细看了题目,的确这可以算是一道生成树的计数问题。(因为任意两点间都只有一条通路)。那么基尔霍夫矩阵便是解决这一问题的方法。

首先,基尔霍夫矩阵是有一个无向图的度矩阵对应地减去一个图的邻接矩阵得到的。如图,这是个无向图。 第二个图是它的度矩阵(度矩阵只有当 i == j 的时候 a[i][j]才有值,其他都为0 );

第三个图是邻接矩阵,第四个图便是基尔霍夫矩阵。









生成矩阵之后,要接着得到它的 n-1 阶主子式(即该n阶矩阵同时去掉第r行,第r列得到的,其中r为任意小于n大于0的一个整数);

最后要对其进行高斯消元得到他的三角形行列式(上三角矩阵)即主对角线下面的数都为0。最后将主对角线上的数都乘起来,便是最终结果。然而蒟蒻并不会证明。

通过基尔霍夫矩阵得出比较小的一些值后,就可以开始找规律了。最终得出的递推式是 F
= F[n-1]*3-F[n-2]+2;(从网上的许多题解中很多人都涉及到一点,如果遇到这种题,很有可能是要递推找规律的);

以下是基尔霍夫矩阵的代码。ca为输入数据组数,n为图的总点数,m为图的总边数。

#include<cstdio>
#include<iostream>
#include<cstring>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define maxn 25
#define LL long long
using namespace std;

LL c[maxn][maxn] = {0}, n, m;

int read()
{
int s = 0, t = 1; char c = getchar();
while( !isdigit(c) ){
if( c == '-' ) t = -1; c = getchar();
}
while( isdigit(c) ){
s = s * 10 + c - '0'; c = getchar();
}
return s * t;
}

LL det()
{
LL ans = 1;
rep(i,1,n-1){
rep(j,i+1,n-1){
while( c[j][i] ){
LL f = c[i][i] / c[j][i];
if( f ) {
rep(l,i,n-1) c[i][l] -= f * c[j][l];
}
rep(l,i,n-1) swap(c[i][l],c[j][l]);
}
}
ans *= c[i][i];
if( !ans ) return 0;
}
return ans < 0? -ans : ans;
}

int main()
{
int ca = read();
while( ca-- ){
memset(c,0,sizeof(c));
n = read(), m = read();
rep(i,1,m){
int u = read(), v = read();
u--, v--;
c[u][u]++, c[v][v]++;
c[u][v]--, c[v][u]--;
}
cout<<det();
}
return 0;
}


以下是BZOJ 1002的代码

#include<cstdio>
#include<iostream>
#include<cstring>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define down(i,j,k) for(int i = j; i >= k; i--)
#define maxn 110
using namespace std;

int mol = 10000;

int read()
{
int s = 0, t = 1; char c = getchar();
while( !isdigit(c) ){
if( c == '-' ) t = -1; c =getchar();
}
while( isdigit(c) ){
s = s * 10+ c - '0'; c = getchar();
}
return s * t;
}

struct data{
int a[40];
data(){
memset(a,0,sizeof(a));
}
};

data datas[maxn];

data mul(data a,int b)
{
rep(i,1,a.a[0]){
a.a[i] *= b;
}
rep(i,1,a.a[0]+2){
a.a[i+1] += a.a[i] / mol;
a.a[i] %= mol;
}
while( a.a[a.a[0]+1] ){
a.a[0]++;
}
return a;
}

data sub(data a,data b)
{
a.a[1] += 2;
down(i,a.a[0],1){
if( a.a[i] < b.a[i] ){
a.a[i+1]--, a.a[i] += mol;
}
a.a[i] -= b.a[i];
}
while( !a.a[a.a[0]] ) {
a.a[0]--;
}
return a;
}

int main()
{
int n = read();
datas[1].a[0] = datas[2].a[0] = 1;
datas[1].a[1] = 1, datas[2].a[1] = 5;
rep(i,3,n){
datas[i] = sub(mul(datas[i-1],3),datas[i-2]);
}
int s = datas
.a[0];
printf("%d", datas
.a[s]);
down(i,s-1,1){
printf("%04d", datas
.a[i] );
}
cout<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: