1. 程式人生 > >【數論專題】

【數論專題】

一、遞迴問題(引子)

1.hanoi雙塔問題

①經典hanoi雙塔

給你n個盤子,3根柱子分別標為ABC,n個盤子從上到下大小遞增,要求大盤不能放在小盤上面且每次只能動一個盤子

問:將盤子全部轉移到C柱需要多少步

要使最大的盤子到C柱,較小的n-1個盤子必須先到B柱,大盤再到C柱,小盤再到C柱,即:

Fn=2Fn1+1,F0=0

我們考慮這個式子的封閉形式

Fn+1=2(Fn1+1)

Gn=Fn+1

Gn=2Gn1,G0=1

Gn=2n

即:

Fn=
2n1

這樣我們就可以在O(logn)的複雜度內解決這個問題了

②複雜情況

如果每次轉移不允許最大的盤子直接到目標柱呢

這樣就需要把小盤子先移到目標柱,再將大盤過中繼柱,小盤迴原柱,大盤到目標柱,小盤到目標柱

可得:Fn=3Fn1+2

類比上式可得封閉形式:

Fn=3n1

③擴充套件

m柱n盤hanoi塔問題求解

設有i個盤子,j個柱子時的答案為f[i][j],則有:

f[i][j]=min(2f[k][j]+f[ik]
[j1])

即:將k個盤子拿走,剩餘盤子拿到目標柱,再轉移k個盤子,組合的最小值即為所求

#include<cstdio>
#include<algorithm>
using namespace std;

const int MAXN=2005,INF=0x7f;

int n,m;
int f[MAXN][MAXN];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=2;i<=m;++i) f[1][i]=1;
    for(int i=3;i<=m;++i) f[2][i]=3
; for(int i=2;i<=n;++i) f[i][3]=f[i-1][3]*2+1; for(int j=4;j<=m;++j){ for(int i=3;i<=n;++i){ int minn=0x7fffffff; for(int k=1;k<i;++k){ minn=min(minn,f[k][j]*2+f[i-k][j-1]); }f[i][j]=minn; } }printf("%d\n",f[n][m]); return 0; }

2.平面分割問題

①直線分割平面

問:n條直線最多將平面分割為幾部分

我們考慮交點對答案的影響

第i條直線最多與其他直線形成i-1個交點,每兩個相鄰交點之間的線段將原區域分為兩份,另外兩條射線各將原平面分為兩份

則有:Fn=Fn1+n

即:

Fn=i=1ni+1=n(n+1)2+1

②角分割平面

問:n個角最多能將平面分割為幾部分

每個角可看作兩條相交直線去掉交點一側後剩下的部分

即去掉的一側不再能夠分割平面,共少分割了2n個

可得:Gn=F2n2n

即:

Gn=2n(2n+1)2+12n=2n2n+1

二、數論

1.整除

①定義

對於整數n,m,若m0且存在整數k,使得km=n,我們就稱m整除n,m是n的約數,n是m的倍數,記作m|n

②性質

  1. a|a
  2. (a|b)(b|a)a=±b