窮舉
最簡單算法,依賴計算機的強大計算能力窮盡每一種可能的情況。窮舉算法效率不高,但是適合一些沒有明顯規律可循的場合。
比如記載於《孫子算經》之中的雞兔同籠問題,適合用窮舉思想解決。
今有雞兔同籠,上有三十五頭,下有九十四足,問雞兔各幾何?
遍歷雞的個數,從0到35個,得到兔的個數,判斷是否滿足條件
int qiongju(int head, int foot, int * chicken, int * rabbit)
{
int re=0, i, j;
for (i = 0; i <= head; i++)//遍歷雞爲i個
{
j = head - i;//兔的個數
if (i * 2 + j * 4 == foot)
{
re = 1;
*chicken = i;
*rabbit = j;
}
}
return re;
}
遞推
遞推根據已知的條件和結果的關係,求解中間結果,根據不斷推進中間結果,求得最後想要的結果。這種條件和結果的關係就如同自變量和因變量一樣,所以遞推思想常用於數學相關領域。
比如斐波拉契數列便適合使用遞推思想來解決
如果一對兩個月大的兔子以後每個月都可以生一對小兔子,而一對新生的兔子出生兩個月後纔可以生兔子。
也就是1月出生到3月才能產崽,那麼假設一年內沒有兔子死亡,一年後共有多少對兔子?
第一個月:1對兔子
第二個月:1對兔子
第三個月:2對兔子
第四個月:3對兔子
第五個月:5對兔子
可以看出,第三月後,N月是之前兩個月兔子的和。
及可以得到因果的公式:F(N)=F(N-1)+F(N-2);
int ditui(int n)//輸入月份,返回當月兔子數量
{
int i, t;
if (n == 1 || n == 2)
{
return 1;
}
else
{
i = ditui(n - 1);
t = ditui(n-2);
return i + t;
}
}
遞歸
遞歸算法是再程序中不斷調用自身來達到解決問題的方法,也是適合於數學計算
遞歸調用,可以直接調用自身,也可以先調用其他函數,再通過其他函數調用自身。
求階乘
5!=5* 4 *3 *2 1
N!=N(N-1)!
int digui(int n)
{
if (n <= 1)
return 1;
else
{
return n*digui(n - 1);
}
}
關於遞推和遞歸的一些區別
遞推:知道第一個,推出下一個,直到達到目的。
遞歸:要知道第一個,需要先知道下一個,直到一個已知的,再反回來,得到上一個,直到第一個。所以遞歸包含遞推和回溯的過程,遞推是遞歸的子集
分治
分而治之,是一種化繁爲簡的思想。
1,將複雜問題劃分爲N個小問題
2,遞歸的求解每個小問題
3,將各個小問題的解合併得到圓問題的解
這裏有30個硬幣,其中一個是假幣,但無法用肉眼區分,只知道假幣比真幣輕一點,如何區分
將所有的硬幣劃分爲兩份,判斷那一份比較輕,再遞推求解,直到只剩下兩個硬幣。
int coin[30] = { 2,2,2,2,2, 1,2,2,2,2, 2,2,2,2,2, 2,2,2,2,2, 2,2,2,2,2, 2,2,2,2,2 };
printf("假幣爲第%d個\n", fenzhi(coin,0,29));
int fenzhi(int *coin,int low ,int high)
{
int i=0, sum1=0, sum2=0, sum3=0,re;
if (low + 1 == high)//最後兩個硬幣比較
{
if (coin[low] < coin[high])
{
re = low + 1;
return re;
}
else
{
re = high + 1;
return re;
}
}
if ((high - low + 1) % 2 == 0)//查詢的硬幣數量爲偶數
{
for (i = low; i <=low + (high - low) / 2; i++)//計算左半部分的重量
{
sum1 = sum1 + coin[i];
}
for ( i = low + (high - low) / 2; i<=high;i++)//計算右半部分的重量
{
sum2 = sum2 + coin[i];
}
if (sum1 > sum2)//左邊重
{
re = fenzhi(coin, low + (high - low) / 2 + 1, high);//遞歸右邊的硬幣
return re;
}
else if (sum1 < sum2)//右邊重
{
re = fenzhi(coin, low, low + (high - low) / 2);//遞歸左邊的硬幣
return re;
}
}
else//查詢的硬幣數量爲奇數
{
for (i = low; i <= low + (high - low) / 2-1; i++)//計算左半部分的重量
{
sum1 = sum1 + coin[i];
}
for (i = low + (high - low) / 2+1; i <= high; i++)//計算右半部分的重量
{
sum2 = sum2 + coin[i];
}
sum3 = coin[low+(high-low)/2];//中間的硬幣重量
if (sum1 > sum2)//左邊重
{
re = fenzhi(coin, low + (high - low) / 2 + 1, high);
return re;
}
else if (sum1 < sum2)//右邊重
{
re = fenzhi(coin, low, low + (high - low) / 2-1);
return re;
}
if (sum1 + sum3 == sum2 + sum3)//中間爲假幣
{
re = low + (high - low) / 2 + 1;
return re;
}
}
}
概率算法思想
依照概率統計的思想來解決問題,在不能得到精確值的領域使用廣
1,將問題轉換爲相應的幾何圖形,求解的問題往往是圖形中的一部分
2,向幾何圖形中隨機撒點。
3,統計在幾何圖形和問題區域的點數,求得結果。
4,精度不夠則繼續撒點
概率算法的4種形式
1,數值概率算法
2,蒙特卡羅算法
3,拉斯維加斯算法
4,舍伍德算法
蒙特卡羅算法求圓周率
ps:蒙特卡洛是一個地名,位於賭城摩納哥,象徵概率。蒙特卡洛(Monte Carlo)方法是由大名鼎鼎的數學家馮·諾伊曼提出的,誕生於上世紀40年代美國的“曼哈頓計劃”。原理是通過大量隨機樣本,去了解一個系統,進而得到所要計算的值。
圖中一個圓面積 S=PI * R^2=PI
圖中一個正方形面積爲 1
只要在陰影方塊中均勻撒點,只要次數過,那麼點數之比S(圓內) / 方塊=PI/4
double gailv(int n)
{
double PI,x,y;
int i, sum=0;
srand(time(NULL));
for (i = 1; i < n; i++)
{
x = (double)rand() / RAND_MAX;
y = (double)rand() / RAND_MAX;
if ((x*x + y*y) <= 1)
{
sum++;
}
}
PI = 4.0*sum / n;
return PI;
}