穷举法
鸡兔同笼问题:今有鸡兔同笼,上有35头,下有94足,问鸡兔各几何?
这个问题曾经我的一个商人朋友跟我讲起过,像大多数人一样,我从数学的角度出发,设鸡有 x 只,兔有 y 只, x + y = 35 并且 2*x + 4*y = 94,正当我忙于计算出结
果的时候,我的一位商人同学跟我说鸡有 23 只,兔有 12只。对于计算的速度让我感到惊讶,然后我就问他,你怎么算这么快?这时,他一本正经的跟我说,你们这些读书
人,脑子都被固化了,思维形成了一种固定的模式,我们生意人就不会这么想。我好奇地问:那你们怎么想?他继续说:我们假设这些动物都训练有素,这是我吹了一下口哨
,然后,所有动物都抬起一只脚,这时鸡1只脚站立,兔子3只脚站立,那就减少了35只脚,这时我再次吹一次口哨,假想这时鸡腾空了,兔子还有2只脚站立在地上,这时还剩
下 94 - 2*35 = 24 只,而兔子只有两只脚站立地上, 24/2 = 12 就是兔子的只数, 35 - 12 = 23 不就是鸡的只数了吗!!!听完后,我恍然大悟,赞叹道:不愧是商人啊!
加入这就是一道实际的应用题,我们也不用太多的追究其解法和算法,可作为一名程序员我们需要知道和了解这样一道问题,如何用代码的形式表现出来,这才是我们追逐的点。
那就让我们一起来看看吧!
#include "stdafx.h"
#include
using namespace std;
int qiongju(int headNum, int footNum, int* chicken, int* rabbit)
{
int result = 0;
// i 代表鸡的 数量 j 代表兔子的数量
for (int i = 0; i <= headNum; i++)
{
for (int j = 0; j <= headNum; j++)
{
if ( (i+j == headNum) && (2*i + 4*j == footNum) )
{
result = 1;
*chicken = i;
*rabbit = j;
}
}
}
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
system("color a");
int headNum = 0;
int footNum = 0;
int chicken = 0;
int rabbit = 0;
printf("请输入兔子和鸡 头 的总数:");
scanf("%d", &headNum);
printf("请输入兔子和鸡 脚 的总数:");
scanf("%d", &footNum);
int result = qiongju(headNum, footNum, &chicken, &rabbit);
if (result)
{
printf("鸡的数量是%d只, 兔子的数量是%d只\n", chicken, rabbit);
}
else
{
printf("此题无解\n");
}
return 0;
}
递推算法思想:根据已有的数据和关系,逐步推到而得到结果。其执行过程如下
1>根据已知结果和关系,求解中间结果。
2>判断是否达到要求,如果没有达到,则继续根据已知结果和关系求解中间结果。如果满足要求,则表示寻找到一个正确答案。
示例:如果一对两个月大的兔子以后每一个月可以生一对小兔子,而一对新生的兔子出生两个月后才可以生小兔子。也就是说,
1月份出生,3月份才可以产仔。那么假定一年内没有产生兔子死亡事件,那么1年后共有多少对兔子?
递推算法:问题分析
第一个月:1对兔子
第二个月:1对兔子
第三个月:2对兔子
第四个月:3对兔子
第五个月:5对兔子
……
∴ 第n个月兔子总数 F(n) = F(n-2) + F(n-1) 注:()内信息为F的下标。
这个问题属于斐波那契数列问题,所以根据上面的分析我们可以写一个算法。
int Fibonacci(int n)
{
if (n==1 || n==2)
{
return 1;
}
else
{
return (Fibonacci(n-1) + Fibonacci(n-2));
}
}
long fact(int n)
{
if (n<=1)
return 1;
else
return n*fact(n-1);
}
分治算法基本思想:将一个计算复杂的问题分为规模较小,计算简单的小问题求解,然后综合各个小问题,得到最终问题的答案。
执行过程:
1>对于一个规模为 N 的问题,若该问题可以容易地解决(比如说规模 N 较小),则直接解决,否则执行下面的步骤。
2>将该问题分解为 M 个规模较小的子问题,这些子问题互相独立,并且与原问题形式相同。
3>递归的解子问题。
4>然后,将各子问题的解合并到原问题的解。
分治算法示例:
问题的提出:
一个袋子里有 30 个硬币,其中一枚是假币,并且假币和真币一模一样,肉眼很难分辨,目前只知道假币比真币重量轻一点。
请问如何区分出假币?
问题分析:
1>首先为每个银币编号,然后将所有的银币等分为两份,放在天平的两边。这样就将区分 30 个硬币的问题,变为区分两堆硬币的问题。
2>因为假银币的分量较轻,因此天平较轻的一侧中一定包含假银币。
3>再将较轻的一侧的硬银币分为两份,重复上述做法。
4>直到剩下 2 枚银币,可用天平直接找出假银币来。
问题解决:
#include "stdafx.h"
#include
using namespace std;
#define MAXNUM 30
/*
* para: coinWeigth 硬币重量数组 low 寻找的起始硬币编号 high 寻找的结束硬币编号
*/
int FalseCoin(int coinWeigth[], int low, int high)
{
int sum1, sum2, sum3;
int re;
sum1 = sum2 = sum3 = 0;
if (low+1 == high)
{
if (coinWeigth[low] < coinWeigth[high])
re = low + 1;
else
re = high + 1;
return re;
}
if ( (high - low + 1) % 2 == 0 ) // coin number is even number(偶数)
{
for (int i = low; i <= low+(high-low)/2; i++)
{
sum1 = sum1 + coinWeigth[i];
}
for (int i = low+(high-low)/2; i <= high; i++)
{
sum2 = sum2 + coinWeigth[i];
}
if (sum1 > sum2)
{
re = FalseCoin(coinWeigth, (high-low)/2+1, high);
return re;
}
else
{
re = FalseCoin(coinWeigth, low, low+(high-low)/2);
return re;
}
}
else // coin number is odd number(奇数)
{
for (int i = low; i <= low+(high-low)/2-1; i++)
{
sum1 = sum1 + coinWeigth[i];
}
for (int i = low+(high-low)/2+1; i <= high; i++)
{
sum2 = sum2 + coinWeigth[i];
}
sum3 = coinWeigth[low+(high-low)/2];
if (sum1 > sum2)
{
re = FalseCoin(coinWeigth, (high-low)/2+1, high);
return re;
}
else
{
re = FalseCoin(coinWeigth, low, low+(high-low)/2-1);
return re;
}
if (sum1 + sum3 == sum2 + sum3)
{
re = low + (high - low) / 2 + 1;
return re;
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
system("color a");
int coinWeight[MAXNUM];
int coinNum;
int pos;
cout<<"分治算法求解假币问题!"<
概率算法
对于概率算法呢,我个人认为适当的了解一下就可以了
蒙特卡罗算法计算 π 示例:(不了解的话,可以去百度百科熟悉一下,这里暂时只给出代码示例)
#include "stdafx.h"
#include
#include
using namespace std;
double MontePI(int n) // 蒙特卡罗算法
{
double PI;
double x, y;
int sum = 0;
srand(time(NULL));
for (int i = 0; i < n; i++)
{
x = (double)rand()/RAND_MAX; // 产生0~1之间的随机数
y = (double)rand()/RAND_MAX; // 产生0~1之间的随机数
if ( (x * x + y * y) <= 1)
{
sum++;
}
}
PI = 4.0*sum/n; // 计算 PI
return PI;
}
int _tmain(int argc, _TCHAR* argv[])
{
system("color a");
int n;
double PI;
printf("蒙特卡罗概率算法计算 π:\n");
printf("输入点的数量:");
scanf("%d", &n);
PI = MontePI(n);
printf("PI=%f\n", PI);
return 0;
}