1. 程式人生 > 實用技巧 >一階卡爾曼濾波演算法的C#實現

一階卡爾曼濾波演算法的C#實現

Hanoi塔問題的原型

問題描述:現在有n個圓盤從上往下從小到大疊在第一根柱子上,要把這些圓盤全部移動到第三根柱子要怎麼移動呢?請找出需要步驟數最少的方案

轉載自https://blog.csdn.net/liujian20150808/article/details/50793101

=====================轉載開始=====================

首先,我們從簡單的例子開始分析,然後再總結出一般規律。

當n = 1的時候,即此時只有一個盤子,那麼直接將其移動至C即可。移動過程就是 A -> C

當n = 2的時候,這時候有兩個盤子,那麼在一開始移動的時候,我們需要藉助B柱作為過渡的柱子,即將A柱最上面的那個小圓盤移至B柱,然後將A柱底下的圓盤移至C柱,最後將B柱的圓盤移至C柱即可。那麼完整移動過程就是A -> B , A -> C , B -> C

當n = 3的時候,那麼此時從上到下依次擺放著從小到大的三個圓盤,根據題目的限制條件:在小圓盤上不能放大圓盤,而且把圓盤從A柱移至C柱後,C柱圓盤的擺放情況和剛開始A柱的是一模一樣的。所以呢,我們每次移至C柱的圓盤(移至C柱後不再移到其他柱子上去),必須是從大到小的,即一開始的時候,我們應該想辦法把最大的圓盤移至C柱,然後再想辦法將第二大的圓盤移至C柱......然後重複這樣的過程,直到所有的圓盤都按照原來A柱擺放的樣子移動到了C柱。

那麼根據這樣的思路,問題就來了:

如何才能夠將最大的盤子移至C柱呢?

那麼我們從問題入手,要將最大的盤子移至C柱,那麼必然要先搬掉A柱上面的n-1個盤子,而C柱一開始的時候是作為目標柱的,所以我們可以用B柱作為"暫存"這n-1個盤子的過渡柱,當把這n-1的盤子移至B柱後,我們就可以把A柱最底下的盤子移至C柱了。

而接下來的問題是什麼呢?

我們來看看現在各個柱子上盤子的情況,A柱上無盤子,而B柱從上到下依次擺放著從小到大的n-1個盤子,C柱上擺放著最大的那個盤子。

所以接下來的問題就顯而易見了,那就是要把B柱這剩下的n-1個盤子移至C柱,而B柱作為過渡柱,那麼我們需要藉助A柱,將A柱作為新的"過渡"柱,將這n-1個盤子移至C柱。

根據上面的分析,我們可以抽象得出這樣的結論:

漢諾塔函式原型:

1 void Hanio(int n,char start_pos,char tran_pos,char end_pos)

那麼我們把n個盤子從A柱移動至C柱的問題可以表示為:

Hanio(n, A, B, C);

那麼從上面的分析得出:

該問題可以分解成以下子問題:

第一步:將n-1個盤子從A柱移動至B柱(藉助C柱為過渡柱)

第二步:將A柱底下最大的盤子移動至C柱

第三步:將B柱的n-1個盤子移至C柱(藉助A柱為過渡柱)

因此完整程式碼如下所示:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int step; //記錄步數
 4 void move(int n, char from, char to) { //將編號為n的盤子由from柱子移動到to柱子(目標柱子)
 5     printf("第%d步:將%d號盤子移動:%c柱子---->%c柱子\n", step++, n, from, to);
 6 }
 7 //漢諾塔遞迴函式引數解釋
 8 //n表示要將多少個"圓盤"從起始柱子移動至目標柱子
 9 //start_pos表示起始柱子, tran_pos表示過渡柱子, end_pos表示目標柱子
10 void Hanio(int n, char start_pos, char tran_pos, char end_pos) {
11     if (n == 1) { //遞迴結束的終點:當n==1時, 只需要直接將圓盤從起始柱子移至目標柱子即可.
12         move(n, start_pos, end_pos);
13     } else {
14         Hanio(n - 1, start_pos, end_pos, tran_pos); //一開始先將n-1個盤子移至過渡柱上
15         move(n, start_pos, end_pos);                //然後再將底下的大盤子直接移至目標柱子即可
16         Hanio(n - 1, tran_pos, start_pos, end_pos); //處理放在過渡柱上的n-1個盤子,此時藉助原來的起始柱作為過渡柱(因為起始柱已經空了)
17     }
18 }
19 int main() {
20     int n;
21     cin >> n;
22     step = 1; //賦初始值
23     Hanio(n, 'A', 'B', 'C');
24     cout << "總步數:" <<  step - 1 << endl;
25     return 0;
26 }

對於n個盤子,移動的總步數為2^n - 1

=====================轉載結束=====================

然後是稍微進階版的藍橋杯的漢諾塔問題

問題描述   如果將課本上的Hanoi塔問題稍做修改:仍然是給定N只盤子,3根柱子,但是允許每次最多移動相鄰的M只盤子(當然移動盤子的數目也可以小於M),最少需要多少次?
  例如N=5,M=2時,可以分別將最小的2個盤子、中間的2個盤子以及最大的一個盤子分別看作一個整體,這樣可以轉變為N=3,M=1的情況,共需要移動7次。 輸入格式   輸入資料僅有一行,包括兩個數N和M(0<=M<=N<=8) 輸出格式   僅輸出一個數,表示需要移動的最少次數 樣例輸入
5 2

樣例輸出

7
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int ans; //移動步數
 4 void move(int n, int m, char a, char b, char c) { 
 5     //引數解釋:將n個盤子,最多一次拿m個,從a柱子開始,以b柱子為過渡,移動到c柱子上
 6     if (n <= m) { //如果可以一次拿完,直接拿
 7         ans++;
 8     } else { //如果一次拿不完
 9         move(n - m, m, a, c, b); //先把上面的n-m個盤子,從a移動到b,以c為過渡。這樣就露出來這m個盤子了
10         ans++; //將這露出來的m個盤子直接拿過去
11         move(n - m, m, b, a, c); //將n-m個盤子從b移動到c,以a為過渡
12     }
13 }
14 int main() {
15     int n, m;
16     cin >> n >> m;
17     move(n, m, 'a', 'b', 'c');
18     cout << ans << endl;
19     return 0;
20 }

然後就是這次的題目了

多了一個塔,用動態規劃

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 15;
 4 int d[N]; //d[n]表示求解n盤3塔的最小步數
 5 int f[N]; //f[n]表示求解n盤4塔問題的最小步數
 6 int main() {
 7     d[1] = 1; //如果只有一個盤子,只需要移動一次
 8     for (int i = 2; i <= N; i++) { //i表示盤子的數量
 9         /*然後接下來這行程式碼就包含很多內容了
10         當現在盤子數量為i的時候
11         可以先把前i - 1個盤子,從a柱移動到b柱上,以c柱為過渡
12         再把最後一個盤子,從a柱直接移動到c柱
13         再把i - 1個盤子,從b柱移動到c柱,以a柱為過渡
14         */
15         d[i] = 2 * d[i - 1] + 1;
16     }
17     memset(f, 0x3f, sizeof(f)); //初始化為正無窮
18     f[0] = 0; //0個盤子不需要做任何操作
19     for (int i = 1; i <= N; i++) {
20         for (int j = 0; j < i; j++) { //列舉一下前j個盤子
21             f[i] = min(f[i], f[j] * 2 + d[i - j]);
22         }
23     }
24     for (int i = 1; i <= 12; i++) {
25         cout << f[i] << endl;
26     }
27     return 0;
28 }

解析:

設d[n]表示求解n盤3塔問題的最小步數

遞推式:d[n] = 2 * d[n-1] + 1

即把前n-1個盤子從A柱移到B柱,然後把A柱上剩的那一個盤子移動到C柱,最後把B柱上的那n-1個盤子移動到C柱上

設f[n]表示求解n盤4塔問題的最小步數

遞推式:f[n] = min{2 * f[i] + d[n - i]}

初始化:f[1] = 1(一個盤子在4塔模式下移動到D柱需要1步)
先把i個盤子在4塔模式下移動到B柱,
然後把n-i個盤子在3塔模式下移動到D柱(因為不能覆蓋到B柱上,就等於只剩下A、C、D柱可以用)
最後把i個盤子在4塔模式下移動到D柱
考慮所有可能的i取最小值,即得到上述遞推公式