zoukankan      html  css  js  c++  java
  • bzoj1002 生成树计数 找规律

    这道题第一眼是生成树计数,n是100,是可以用O(n^3)的求基尔霍夫矩阵的n-1阶的子矩阵的行列式求解的,但是题目中并没有说取模之类的话,就不好办了。

    用高精度?有分数出现。

    用辗转相除的思想,让它不出现分数。但过程中会出现负数,高精度处理负数太麻烦。

    用Python打表?好吧,Python还不熟,写不出来。。。。。

    所以,如果这道题我考场上遇到,最多用double骗到n<=20的情况的部分分。

    最终只能求助于题解了。。。

    好像是通过观察行列式的特点,推导出关于答案f(n)的递推式(f(n)=3*f(n-1)-f(n-2)+2)

    这道题就这样水过了,收获是:

      1、题目可能属于某一类问题,该类问题又有通法可解,但题目一般不能直接套用之,此时就只能观察题目较之一般问题的特殊之处,尝试利用它帮助解题。

      2、当1行不通时,可以先用暴力把规模较小的解跑出来,再看看可否推出规律。

    回顾一下高精:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #define M 10
     5 using namespace std;
     6 
     7 struct Num {
     8     int v[100], len;
     9     Num(){}
    10     Num( int n ) {
    11         memset( v, 0, sizeof(v) );
    12         if( n==0 ) {
    13             len = 1;
    14             return;
    15         }
    16         len = 0;
    17         while( n ) {
    18             len++;
    19             v[len] = n%M;
    20             n /= M;
    21         }
    22     }
    23     Num operator+( const Num &b ) const {
    24         Num rt(0);
    25         rt.len = max( len, b.len ) + 1;
    26         for( int i=1; i<=rt.len; i++ ) {
    27             rt.v[i] += v[i]+b.v[i];
    28             rt.v[i+1] += rt.v[i]/M;
    29             rt.v[i] %= M;
    30         }
    31         while( rt.len>1 && rt.v[rt.len]==0 ) rt.len--;
    32         return rt;
    33     }
    34     Num operator-( const Num &b ) const {
    35         Num rt(0);
    36         rt.len = len;
    37         for( int i=1; i<=rt.len; i++ ) {
    38             rt.v[i] += v[i]-b.v[i];
    39             if( rt.v[i]<0 ) {
    40                 rt.v[i]+=M;
    41                 rt.v[i+1]--;
    42             }
    43         }
    44         while( rt.len>1 && rt.v[rt.len]==0 ) rt.len--;
    45         return rt;
    46     }
    47     int count_bit( int b ) const {
    48         int rt = 0;
    49         while( b ) {
    50             rt++;
    51             b/=M;
    52         }
    53         return rt;
    54     }
    55     Num operator*( int b ) const {
    56         Num rt(0);
    57         rt.len = len+count_bit(b)+1;    //    b==3
    58         for( int i=1; i<=rt.len; i++ ) {
    59             rt.v[i] += v[i]*b;
    60             rt.v[i+1] += rt.v[i]/M;
    61             rt.v[i] %= M;
    62         }
    63         while( rt.len>1 && rt.v[rt.len]==0 ) rt.len--;
    64         return rt;
    65     }
    66     void print() {
    67         for( int i=len; i>=1; i-- )
    68             printf( "%d", v[i] );
    69         printf( "
    " );
    70     }
    71 };
    72 
    73 int n;
    74 Num dp[110];
    75 
    76 int main() {
    77     scanf( "%d", &n );
    78     dp[1] = Num(1);
    79     dp[2] = Num(5);
    80     for( int i=3; i<=n; i++ )
    81         dp[i] = dp[i-1]*3 +Num(2) - dp[i-2];
    82     dp[n].print();
    83 }
    View Code

    ——————————————————————————————————————————

    去补习了一下python,用python写了一个用辗转相除思想算行列式的算法(感觉python还是挺快的,还有高精度支持)

     1 #!/usr/bin/python
     2 
     3 from math import *
     4 
     5 
     6 def swap( a, b ):
     7     return b, a
     8 def abs( a ) :
     9     if a<0 :
    10         return -a
    11     else:
    12         return a
    13 def det( a, n ):
    14     for i in range(0,n):
    15         if a[i][i]==0:
    16             return 0
    17         for j in range(i+1,n):
    18             while a[j][i]!=0 : 
    19                 d = a[i][i]//a[j][i]
    20                 for k in range(i,n) :
    21                     a[i][k] = a[i][k]-a[j][k]*d
    22                     a[j][k],a[i][k] = swap( a[j][k],a[i][k] )
    23     ans = 1
    24     for i in range(0,n):
    25         ans = ans * a[i][i]
    26     return abs(ans)
    27 
    28 def mod( a, m ):
    29     return (a%m+m)%m
    30 
    31 def main():
    32     for n in range( 1, 101 ):
    33         if n==1 :
    34             print 1
    35             continue
    36         if n==2 :
    37             print 5
    38             continue
    39 
    40         i = j = 0
    41         a = [ [ 0 for j in range(n) ] for i in range(n) ]
    42         i = 0
    43         for i in range(0,n):
    44             a[i][i] = 3
    45             a[i][mod(i-1,n)] = -1
    46             a[i][mod(i+1,n)] = -1
    47         print det(a,n)
    48 main()
    View Code

    将文件保存到bzoj1002.py,执行

      chmod +x hzoj1002.py

      ./hzoj1002.py

  • 相关阅读:
    linux sysfs (2)
    微软——助您启动云的力量网络虚拟盛会
    Windows Azure入门教学系列 全面更新啦!
    与Advanced Telemetry创始人兼 CTO, Tom Naylor的访谈
    Windows Azure AppFabric概述
    Windows Azure Extra Small Instances Public Beta版本发布
    DataMarket 一月内容更新
    和Steve, Wade 一起学习如何使用Windows Azure Startup Tasks
    现实世界的Windows Azure:与eCraft的 Nicklas Andersson(CTO),Peter Löfgren(项目经理)以及Jörgen Westerling(CCO)的访谈
    正确使用Windows Azure 中的VM Role
  • 原文地址:https://www.cnblogs.com/idy002/p/4293556.html
Copyright © 2011-2022 走看看