<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
        版權申明:本文為博主窗戶(Colin Cai)原創,歡迎轉帖。如要轉貼,必須注明原文網址
      
         http://www.rzrgm.cn/Colin-Cai/p/18931900.html
      
        作者:窗戶
      
        QQ/微信:6679072
      
        E-mail:6679072@qq.com

      本節在上一節的結論基礎上,通過程序對于給定階數生成該階下所有可能的Abel群。

       

      有限Abel群結構定理

      我們再回憶一下有限Abel群的所有可能結構:

      任何一個階數大于1的有限Abel群都可以同構為數個階數大于1的循環群的直積$Z_{a_1} \otimes Z_{a_2} \otimes ... \otimes Z_{a_n}$,并滿足各循環群的階數從左到右為約數關系,也就是$a_1|a_2|...|a_n$,另外$a_1,a_2,...,a_n$相乘等于原Abel群的階數。

      另外,

      如果$a_1,a_2,...,a_n$都是大于1的整數,$b_1,b_2,...,b_m$也都是大于1的整數,

      $a_1|a_2|...|a_n$,并且$b_1|b_2|...|b_m$,

      那么$Z_{a_1} \otimes Z_{a_2} \otimes ... \otimes Z_{a_n} \cong Z_{b_1} \otimes Z_{b_2} \otimes ... \otimes Z_{b_m}$

      的充要條件是

      $m=n \land a_1=b_1 \land a_2=b_2 \land ... \land a_n = b_n$

      也就是只要有一個循環群不同,兩個Abel群就不同構。

      比如$72$階Abel群,總共有以下幾個同構:

      $Z_{72}$

      $Z_2 \otimes Z_{36}$

      $Z_3 \otimes Z_{24}$

      $Z_6 \otimes Z_{12}$

      $Z_2 \otimes Z_2 \otimes Z_{18}$

      $Z_2 \otimes Z_6 \otimes Z_6$

      以下,我們用程序實現,還是繼續選擇Python語言。

       

      生成器遞歸實現

      我們首先考慮生成器,我想程序員們大多對于此問題應該有遞歸的直覺。遞歸很多時候在于問題的分解。

      Python的生成器其實是有點拗口的,它從語法上并非那么自然,使得像我這樣有點語法潔癖的人,總覺得有點疙瘩。

      比如如下代碼:

      def f(x):
          if x <= 0:
              return -x
          else:
              for i in range(x):
                  yield i
      for i in f(10):
          print(i)
      print(f(-10))

      它最后對于f(-10)的返回居然是<generator object f at 0x7f38ee923740>

      Python對其解釋是,一日生成器終身生成器,也就是生成器和函數是不一樣的東西。好吧,唐僧取經最后都有幾卷經書曬在礁石上撕不下來,世間很難完美。

      生成器中,部分流是從另外一個生成器中來的話,可以

      for i in generator2(args):

          yield i

      不可以直接

      generator2(args)

      因為如此,Python會當成只是執行了一個函數。比較簡潔的寫法是

      yield from generator2(args)

      以上可以用于我們生成器的遞歸,而我們工作的核心在于如何分解任務。

      其實,DC(分治)對一個問題可能有多種分解方式,這里我們就想一種最簡單明了的。

      打個比方,我們來求$180$的所有可能。

      那么,它可以是單獨的

      $(180)$

      也可能是

      $(2 ...)$

      也可能是

      $(3 ...)$

      也可能是

      $(6 ...)$

      注意,如果至少有兩個數,那么后面至少會有一個數,而且必須是前面數的倍數,也就是說,第一個數的平方必須是整體的約數,

      $2^2|180$

      $3^2|180$

      $6^2|180$

      當然,我們不用考慮$1$(這種平凡的Abel群我們可以當特例直接排除)的分解,那么,既然要考慮遞歸,就要更一般的考慮下去

      假如我們已經把數字$N$分解到

      $(a_1,a_2...a_n,...)$

      當然,其中

      $a_1|a_2...|a_n$

      假設能分解到這步,也就是后面至少還有一項是$a_n$的倍數,從而

      $(\prod_{i=1}^{i\le n}{a_i})*a_n|N$

      也就是

      $(a_1,a_2...a_n,\frac{N}{\prod_{i=1}^{i\le n}{a_i}})$

      是后面僅剩一項的情況

      如果

      $\exists a_{n+1}:a_n|a_{n+1} \land (\prod_{i=1}^{i\le n}{a_i})*a_{n+1}^2|N$

      那,我們可以繼續安插進下一項,這里找到的$a_{n+1}是合適的下一項,

      $(a_1,a_2...a_n,a_{n+1}...)$

      其實也就是,如果

      $\exists m \in Z^+ : (m*a_n)^2|\frac{N}{\prod_{i=1}^{i\le n}{a_i}}$

       那么是可以繼續安插進下一項,

      $(a_1,a_2...a_n,a_{n+1}...)$

      于是,我們先給定生成器用來生成$(a_1,a_2...,a_n)$開頭的所有的有效分解。

      按照剛才的分析,生成器gen(remained, a)可以如下編寫,其中這里的remained則是剛才的$\frac{N}{\prod_{i=1}^{i\le n}{a_i}}$

      def gen(remained, a):
          #自身是一個合理的分解
          yield a + [remained]
          if a:
              #如果a里面有元素,那么挨個m*a[-1]遍歷試除一下
              x = a[-1]
              while x * x <= remained:
                  if remained % (x * x) == 0:
                      yield from gen(remained // x, a + [x])
                  x += a[-1]
          else:
              #如果a是空列,那么挨個大于等于1的整數遍歷試除一下
              x = 2
              while x * x <= remained:
                  if remained % (x * x) == 0:
                      yield from gen(remained // x, a + [x])
                  x += 1

      然后,最終的我們要的生成器,

      gen_all_abel = lambda N:gen(N,[])

      嗯,這里可以像函數一樣,lambda也是支持生成器的。

       

      因式分解

      考慮上面慢在哪里,找因子是依次這樣試除找過來,如果我們一早知道因式分解,應該是可以提升效率的。

      因式分解就采用最簡單的試除如下:

      def factor(N):
          ret = []
          n = 2
          while n * n <= N:
              if N % n == 0:
                  k = 0
                  while N % n == 0:
                      N //= n
                      k += 1
                  ret.append((n, k))
              n += 1
          if N != 1:
              ret.append((N, 1))
          return ret

      所用算法沒啥大技巧,唯一要提的也就是和之前一樣,合數一定有一個約數小于等于自己的平方根。

      有了這個之后,前面的算法可以先因式分解,然后再不需要依次試除,此處省略優化后的實現,由讀者自己去思考吧。

       

      迭代器字序列實現

      我們再來考慮迭代器序列的實現。

      首先,我們意識到因式分解的好處,自然有很多計算基于因式分解。我們可以建立一個類來實現因式分解的運算。

      class Factor(object):
          def __init__(self, arg=[]):
              if isinstance(arg, list): #傳入為因式分解list
                  self.factor_list = arg
              elif isinstance(arg, Factor): #傳入為別的Factor對象,復制對象
                  self.factor_list = [i for i in arg.factor_list]
              elif isinstance(arg, int): #傳入是數字
                  self._factor(arg)
          def _factor(self, n):
              self.factor_list = []
              x = 2
              while (x * x <= n):
                  if n % x == 0:
                      k = 0
                      while n % x == 0:
                          n //= x
                          k += 1
                      self.factor_list.append((x, k))
                  x += 1
              if n != 1:
                  self.factor_list.append((n, 1))

      上面Factor()不帶參數時,實際上等同于Factor(1)。

      再加入一些運算,包括轉整數、乘法、乘方、除法、n次根等,而加、減法我們并不關心,畢竟對我們問題的解決沒有任何幫助。另外,我們希望這些因式分解對象使用平常的Python運算符,比如乘法的*,乘方的**,除法的/,這樣可以做到運算符的多態(polymorphic),從而達到泛型(generic)。這一點在別的語言里也可以做到,比如C++我們可以為各個類型重載運算符、函數,再比如Haskell的typeclass也可以讓各個類型使用相同的函數名、運算符。我們在這里使用Python,語言級別提供了自定義class對運算符的支持,那就是魔術方法(magic method),也就是那些兩個下劃線開頭兩個下劃線結尾的方法,比如__add__(用來重載加法),__mul__(用來重載乘法)。我們把乘方和n次方根都用乘方符號(**)來表示,但浮點數一般并不能精確的反應分數,我們就采用Python自帶的分數類(from fractions import Fraction)。

      考慮一下開方運算,對于解題有幫助的開方運算定義如下:a開n次方意思是$max\{x|x \in Z^+ \land x^n|a\}$

      比如$72$開$2$次方結果為$6$

      在這樣的定義下,我們重載__int__, __mul__, __truediv__, __power__以實現Factor對象的加法、乘法、除法、乘方

      其中除法我們只考慮整除的情況,這些并不難實現,讀者可以自行實現。

      再者,我們自然得定義一下序列以便把所有的分解排成一個全序集。

      比如,我們考慮$5400$的所有分解,如下:

      $(5400)$
      $(2 \quad 2700)$
      $(3 \quad 1800)$
      $(6 \quad 900)$
      $(5 \quad 1080)$
      $(10 \quad 540)$
      $(15 \quad 360)$
      $(30 \quad 180)$
      $(2 \quad 2 \quad 1350)$
      $(2 \quad 6 \quad 450)$
      $(2 \quad 10 \quad 270)$
      $(2 \quad 30 \quad 90)$
      $(3 \quad 3 \quad 600)$
      $(3 \quad 6 \quad 300)$
      $(3 \quad 15 \quad 120)$
      $(3 \quad 30 \quad 60)$
      $(6 \quad 6 \quad 150)$
      $(6 \quad 30 \quad 30)$

      考慮$5400$因式分解為$2^3\times 3^3 \times 5^2$

      它有三個質因數$2,3,5$

      將上面的每一行里的每個數都寫為$2,3,5$的冪乘積(沒有則填0次冪),并且順序為$5,3,2$這樣從大到小,那么則為

      $({5}^{2} \times {3}^{3} \times {2}^{3})$
      $({5}^{0} \times {3}^{0} \times {2}^{1} \quad {5}^{2} \times {3}^{3} \times {2}^{2})$
      $({5}^{0} \times {3}^{1} \times {2}^{0} \quad {5}^{2} \times {3}^{2} \times {2}^{3})$
      $({5}^{0} \times {3}^{1} \times {2}^{1} \quad {5}^{2} \times {3}^{2} \times {2}^{2})$
      $({5}^{1} \times {3}^{0} \times {2}^{0} \quad {5}^{1} \times {3}^{3} \times {2}^{3})$
      $({5}^{1} \times {3}^{0} \times {2}^{1} \quad {5}^{1} \times {3}^{3} \times {2}^{2})$
      $({5}^{1} \times {3}^{1} \times {2}^{0} \quad {5}^{1} \times {3}^{2} \times {2}^{3})$
      $({5}^{1} \times {3}^{1} \times {2}^{1} \quad {5}^{1} \times {3}^{2} \times {2}^{2})$
      $({5}^{0} \times {3}^{0} \times {2}^{1} \quad {5}^{0} \times {3}^{0} \times {2}^{1} \quad {5}^{2} \times {3}^{3} \times {2}^{1})$
      $({5}^{0} \times {3}^{0} \times {2}^{1} \quad {5}^{0} \times {3}^{1} \times {2}^{1} \quad {5}^{2} \times {3}^{2} \times {2}^{1})$
      $({5}^{0} \times {3}^{0} \times {2}^{1} \quad {5}^{1} \times {3}^{0} \times {2}^{1} \quad {5}^{1} \times {3}^{3} \times {2}^{1})$
      $({5}^{0} \times {3}^{0} \times {2}^{1} \quad {5}^{1} \times {3}^{1} \times {2}^{1} \quad {5}^{1} \times {3}^{2} \times {2}^{1})$
      $({5}^{0} \times {3}^{1} \times {2}^{0} \quad {5}^{0} \times {3}^{1} \times {2}^{0} \quad {5}^{2} \times {3}^{1} \times {2}^{3})$
      $({5}^{0} \times {3}^{1} \times {2}^{0} \quad {5}^{0} \times {3}^{1} \times {2}^{1} \quad {5}^{2} \times {3}^{1} \times {2}^{2})$
      $({5}^{0} \times {3}^{1} \times {2}^{0} \quad {5}^{1} \times {3}^{1} \times {2}^{0} \quad {5}^{1} \times {3}^{1} \times {2}^{3})$
      $({5}^{0} \times {3}^{1} \times {2}^{0} \quad {5}^{1} \times {3}^{1} \times {2}^{1} \quad {5}^{1} \times {3}^{1} \times {2}^{2})$
      $({5}^{0} \times {3}^{1} \times {2}^{1} \quad {5}^{0} \times {3}^{1} \times {2}^{1} \quad {5}^{2} \times {3}^{1} \times {2}^{1})$
      $({5}^{0} \times {3}^{1} \times {2}^{1} \quad {5}^{1} \times {3}^{1} \times {2}^{1} \quad {5}^{1} \times {3}^{1} \times {2}^{1})$

      取指數,則為以下的列

      $2, 3, 3$
      $0, 0, 1, 2, 3, 2$
      $0, 1, 0, 2, 2, 3$
      $0, 1, 1, 2, 2, 2$
      $1, 0, 0, 1, 3, 3$
      $1, 0, 1, 1, 3, 2$
      $1, 1, 0, 1, 2, 3$
      $1, 1, 1, 1, 2, 2$
      $0, 0, 1, 0, 0, 1, 2, 3, 1$
      $0, 0, 1, 0, 1, 1, 2, 2, 1$

      $...$

      這個順序關系一目了然,是以指數序列大小的順序排列的。

      我們考慮用這個順序來取出一個正整數所有的正約數,讓Factor加入一個next函數,來取下一個約數。

      于是以下代碼遍歷參數n的所有正約數:

      def traverse_all_divisors(n):
          a = Factor(n)
          b = Factor()
          print(int(b))
          #循環獲得排序下的下一個約數直到不再有約數
          while a.next(b):
              print(int(b))

      比如,traverse_all_divisors(72)會依次打印72所有的正約數

      1
      2
      4
      8
      3
      6
      12
      24
      9
      18
      36
      72

      以上來看并非數值從小到大,但是如果分解成指數的形式

      1 [0, 0]
      2 [0, 1]
      4 [0, 2]
      8 [0, 3]
      3 [1, 0]
      6 [1, 1]
      12 [1, 2]
      24 [1, 3]
      9 [2, 0]
      18 [2, 1]
      36 [2, 2]
      72 [2, 3]

      上面則很容易看出其升序

      Factor的next方法實現并不難,從低位往高位依次遍歷,和數數一樣的做法。

          def next(self, s):
              len_self = len(self.factor_list)
              len_s = len(s.factor_list)
              #用index_self和index_s作為下標來遍歷
              index_self = 0
              index_s = 0
              #依次來比較self和s
              while True:
                  if index_self >= len_self:
                      return False
                  xa, ya = self.factor_list[index_self]
                  index_self += 1
                  if index_s >= len_s:
                      s.factor_list = [(xa, 1)]
                      return True
                  xb, yb = s.factor_list[index_s]
                  index_s += 1
                  if xa != xb or ya != yb:
                      break
              if xa != xb:
                  s.factor_list = [(xa, 1), (xb, yb)] + s.factor_list[index_s:]
                  return True
              #ya != yb
              s.factor_list = [(xa, yb + 1)] + s.factor_list[index_s:]
              return True

      Python沒有do/while結構,上面的while True與最后if-break是模擬do/while的寫法。

      有了以上完整的Factor實現之后,我們就可以按照上述所說的順序來依次生成所有的分解,串成一個迭代器。

      Python對迭代器的實現其實很簡單:迭代器是一個class,實現__iter__方法返回self,__next__方法每次調用返回下一個值,當沒有下一個值則發出StopIteration異常。

      按照上述所說,以下給出了gen_abel的構造函數,__iter__和__next__:

      class gen_abel(object):
          def __init__(self, n):
              self.whole_factor = Factor(n)
              self.next_value = [self.whole_factor]
          def __iter__(self):
              return self
          def __next__(self):
              if self.next_value:
                  ret = list(map(int, self.next_value))
                  self._next()
                  return ret
              raise StopIteration

      可以看到,保留兩個屬性,一個是whole_factor來表示n的因式分解,另一個next_value是下一次next所得到的結果,為了區分是否下一次next還有結果,則此處我們先約定沒有下一次next結果則next_value為None。按照之前所說的順序,長度為1的分解是排在最開始的,所以構造函數里給next_value的初值為 [self.whole_factor]。

      接下去最后的任務就是實現這個_next函數了,它就是找whole_factor的下一個分解

          def _next(self):
              length = len(self.next_value)
              #依次調整self.next_value[i:]的分解
              for i in range(length - 2, -1, -1):
                  if self._try_next(length, i):
                      return
              #只能分解長度加1
              length += 1
              for a, k in self.whole_factor.factor_list:
                  #只需要找到第一個質數的冪不小于length的即可完成分解
                  if k >= length:
                      t = Factor([(a, 1)])
                      t2 = self.whole_factor / Factor([(a, length - 1)])
                      self.next_value = [t] * (length - 1) + [t2]
                      return
              #實在沒有了,則遍歷完了所有分解,設置為None
              self.next_value = None

      _try_next的實現

          def _try_next(self, length, index):
              #把最后幾項乘起來,嘗試重新分配
              t = Factor()
              for i in self.next_value[index:]:
                  t *= i
              #r1是總共還可以分配的
              r1 = Factor(t)
              if index != 0:
                  r1 /= Factor(self.next_value[index - 1]) ** (length - index)
              #這個時候就是開方運算了
              r1 = r1 ** Fraction(1, length - index)
              r2 = Factor(self.next_value[index])
              if index != 0:
                  r2 /= self.next_value[index - 1]
              #r2找個緊接著排序的值
              if r1.next(r2):
                  ret = self.next_value[0:index]
                  if index != 0:
                      r2 *= self.next_value[index - 1]
                  for j in range(length - index - 1):
                      ret.append(r2)
                  ret.append(t / r2 ** (length - index - 1))
                  self.next_value = ret
                  return True
              return False

       

      Scheme實現

      我鐘愛的Lisp,怎么可以少得了它呢,以下鏈接是我寫的實現代碼。

       Scheme實現

      它用了Lisp的一種惰性計算模型——流(stream),其實和Python的生成器/迭代器沒啥本質上的區別。

      三個實現包含著之前的兩種Python實現,以及未寫的基于因式分解提速的遞歸生成器同樣算法。

      posted on 2025-07-31 12:06  窗戶  閱讀(298)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 亚欧成人精品一区二区乱| 在线涩涩免费观看国产精品| 一区二区三区岛国av毛片| 国产成人8X人网站视频| 日本三级香港三级人妇99| 少妇无套内谢免费视频| 亚洲性日韩精品一区二区| 国产精品自在拍首页视频| 午夜天堂一区人妻| 色欲久久综合亚洲精品蜜桃| 大陆精大陆国产国语精品| 日本韩国一区二区精品| 国产日产免费高清欧美一区| 中文字幕国产精品一二区| 国产96在线 | 亚洲| 国产人妻高清国产拍精品| 国产一区一一区高清不卡| 中国女人和老外的毛片| 亚洲国产成人综合自在线| 中国女人熟毛茸茸A毛片| 99久久久国产精品免费无卡顿| 国产午夜精品视频在线播放| 精品日韩人妻中文字幕| 宜良县| 亚洲精品中文综合第一页| 国产suv精品一区二区四| 久久国产精品-国产精品| 综合亚洲网| 国产盗摄xxxx视频xxxx| 精品亚洲精品日韩精品| 九九久久人妻一区精品色| 伊人成人在线视频免费| 亚洲精品久久久久久无码色欲四季| 久久涩综合一区二区三区| 日韩精品一区二区午夜成人版| 国产福利视频区一区二区| 久女女热精品视频在线观看| 日韩精品国产另类专区| 少妇被日自拍黄色三级网络| 夜鲁鲁鲁夜夜综合视频| 97欧美精品系列一区二区|