1、枚举:本质就是从所有候选答案中去搜索正确的解,使用该算法需要满足两个条件:(1)可预先确定候选答案的数量;(2)候选答案的范围在求解之前必须有一个确定的集。
#include<stdio.h>
#include<windows.h>
/*
*枚举法:实现给出任意五个数和结果,利用加减乘除使等式成立
*考虑1:优先级
*考虑2:除法右边不能为0;
*/
int judge(int num[],int len,int result)
{
int op[4] = { '+', '-', '*', '/' };
int exp[4];
int count = 0;
for (exp[0] = 0; exp[0] < 4; exp[0]++){//第一个空位的操作符判断
if (exp[0] == 3 && num[1] == 0){//当操作数是/时右边不能为0
return 0;
}
for (exp[1] = 0; exp[1] < 4; exp[1]++){//第二个空位的操作符判断
if (exp[1] == 3 && num[2] == 0){
return 0;
}
for (exp[2] = 0; exp[2] < 4; exp[2]++){//第三个空位的操作符判断
if (exp[2] == 3 && num[3] == 0){
return 0;
}
for (exp[3] = 0; exp[3] < 4; exp[3]++){//第四个空位的操作符判断
if (exp[3] == 3 && num[4] == 0){
return 0;
}
int flag = 1;
int sum = 0;
int index = num[0];
for (int j = 0; j < 4; j++){
switch (op[exp[j]]){
case '+':
sum = sum + flag*index;
index = num[j + 1];
flag = 1;
break;
case '-':
sum = sum + flag*index;
index = num[j + 1];
flag = -1;
break;
case '*':
index = index*num[j + 1];//优先级执行
break;
case '/':
index = index/num[j + 1];
break;
}
}
if ((sum + flag*index) == result){//已执行完乘和除
count++;
for (int j = 0; j < 4; j++){
printf("%d%c", num[j], op[exp[j]]);
}
printf("%d=%d\n", num[4], result);
}
}
}
}
}
if (count == 0){
printf("无匹配结果!\n");
}
return 0;
}
int main()
{
printf("请输入5个操作数:");
int num[5];
int i = 0;
for (; i < 5; i++){
scanf_s("%d", &num[i]);
}
printf("请输入结果:");
int result;
scanf_s("%d", &result);
judge(num, 5, result);
system("pause");
return 0;
}
1、递推和递归
相对于递归算法,递推算法免除了数据进出栈(递归运算运行时的开销是它的一大缺点:参数必须压到堆栈中,为局部变量分配内存空间)的过程,也就是说,不需要函数不断的向边界值靠拢,而直接从边界出发,直到求出函数值。
2、递推:给定一个数的序列H0,H1,…,Hn,…若存在整数n0,使当n>n0时,可以用等号(或大于号、小于号)将Hn与其前面的某些项Hi(0<i<n)联系起来,这样的式子就叫做递推关系。
3、递归:就是一种直接或间接调用自己的算法,它所需要的两个特性:①存在限制条件,当符合这个条件时递归便不再继续;②每次递归调用之后越来越接近这个限制条件。
4、递归与迭代
由于递归的开销太大与浪费,当递归是尾部递归(即为递归调用是函数的最后一项任务)时,可以很容易的转为迭代算法相对有效的进行运算。
5、迭代(辗转):数值分析中通过从一个初始估计出发寻找一系列近似解来解决问题(一般是解方程或者方程组)的过程,为实现这一过程所使用的方法统称为迭代法,它
用计算机解决问题的一种基本方法,它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。
#include<stdio.h>
#include<Windows.h>
#pragma warning(disable:4996)
//斐波拉契数列(兔子数列):每个数都等于它前两个数之和
//递推算法:求斐波拉契数列的某一项
int derivate(int fib[], int n)
{
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i <= n; i++){
fib[i] = fib[i - 1] + fib[i - 2];
}
return fib[n];
}
//递归算法:求斐波拉契数列的某一项
//不建议用开销空间大且浪费空间严重,效率低
int recurse(int n){
if (n == 0){
return 0;
}
if (n == 1 || n == 2){
return 1;
}
return recurse(n - 1) + recurse(n - 2);//尾部递归
}
//迭代算法:求斐波拉契数列的某一项
//最佳:相对于递推,定义局部变量少,开销空间小,效率高
int iterate(int n)
{
int first = 1;
int second = 1;
int sum = 0;
if (!n){
return 0;
}
else if (n <= 2){
return 1;
}
else{
while (n > 2){
sum = first + second;
first = second;
second = sum;
n--;
}
}
return sum;
}
int main()
{
int n;
scanf("%d", &n);
int *fib;
fib = (int*)malloc(n*sizeof(int));
printf("%d\n", derivate(fib, n));
printf("%d\n", recurse(n));
printf("%d\n", iterate(n));
system("pause");
return 0;
}
1
、
分治算法:
基本思想:将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同
解题的一般步骤:
(1)分解,将要解决的问题划分成若干规模较小的同类问题;
(
2)求解,当子问题划分得足够小时,用较简单的方法解决;
(3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。
#include<stdio.h>
#include<Windows.h>
#pragma warning(disable:4996)
#define N 64
int arr[N+1][N+1] = { 0 };
//分治算法:安排比赛选手的比赛日程
//思路:对于参赛选手为2的次方情况,将四个分为一组进行安排
void divideAndSolve(int k, int n)
{
if (n == 2){
arr[k][1] = k;//参赛选手
arr[k][2] = k + 1;//对战选手
arr[k + 1][1] = k + 1;
arr[k + 1][2] = k;
}
else{
divideAndSolve(k, n / 2);//1,2
divideAndSolve(k + n / 2, n / 2);//3,4
for (int i = k; i < k + n / 2; i++){
for (int j = n / 2 + 1; j <= n; j++){
arr[i][j] = arr[i + n / 2][j - n / 2];
}
}
for (int i = k + n / 2; i <= k + n; i++){
for (int j = n / 2 + 1; j <= n; j++){
arr[i][j] = arr[i - n / 2][j - n / 2];
}
}
}
}
int main()
{
int n;
scanf("%d", &n);
divideAndSolve(1, n);
printf("编号\t");
for (int i = 1; i < n; i++){
printf("第%d天\t", i);
}
printf("\n");
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
printf("%d\t", arr[i][j]);
}
printf("\n");
}
system("pause");
return 0;
}