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] = 1; fib[1] = 1; for (int i = 2; i < n; i++){ fib[i] = fib[i - 1] + fib[i - 2]; } return fib[n-1]; } //递归算法:求斐波拉契数列的某一项 //不建议用开销空间大且浪费空间严重,效率低 int recurse(int n){ if (n <= 2){ return 1; } return recurse(n - 1) + recurse(n - 2);//尾部递归 } //迭代算法:求斐波拉契数列的某一项 //最佳:相对于递推,定义局部变量少,开销空间小,效率高 int iterate(int n) { int first = 1; int before = 1; int pre = 0; int i = 1; while (i <= n - 2){ pre = before + first; first = before; before = pre; i++; } return pre; } 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; }