1.穷举法思想,在可能的解空间种穷举每一种可能的解,并对每种可能的解进行判断,从中得到问题的答案.
优缺点:用时间上的牺牲换来了解的全面性保证。
eg:寻找指定区间的素数
2.递归与分治思想
递归:直接或者间接的调用原算法本身的一种算法。
设计递归注意点:
(1) 每个递归函数必须有一个非递归定义的初始值,作为递归结束标志。
(2) 设计递归算法的时候,要解决的问题必需具有递归性。
(3) 递归算法运行效率低,时间和空间复杂度比较高,因此设计到对于一些对时间和空间要求比较高的程序,建议使用非递归算法
分治思想:解决一些规模较大的问题时,常常将问题进行分解成规模较小的同类问题,然后将小问题逐个解决,最终也就将整个大问题解决。比如折半查找。
3.贪心算法思想
所谓的贪心算法,总是在做出当前看来是最好的选择的一种方法,比如有三种硬币,面值分别为1元,5角,1角,如果给客户找2元7角,请问怎么找才能使硬币数目最少。
方案:首先找一个面值不超过2元7角的最大硬币,即1元硬币。
然后从2元7角种减去1元,得到1元7角,再找一个面值不超过1元7角的最大硬币,即1元硬币,以此类推,
我们长用的哈夫曼编码算法,最小生成树算法,求解最短路径算法都属于贪心算法思想。
eg:最优装船问题
有一批集装箱要装入一个载质量为C的货船中,每个集装箱的质量由用户自己输入,在货船的体积不限的前提下,如何装载集装箱才能尽可能多的将集装箱装入货船中。
基本思想:在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当搜索到某一个结点时,要先判断该结点是否包含问题的解,如果包含,从该结点继续探索,如果不包含,那就说明以该结点为根结点的字树一定不包含问题的最终解,因此要跳过对该结点为根的子树的探索,逐层向其祖先结点回溯。
eg:N皇后问题,求解如何在一个N * N 的棋盘上无冲突地摆放N个皇后棋子,在任意一个皇后所在位置的水平,竖直,以及45度斜线上都不能出现出现其它皇后的棋子。
5.概率算法
概率算法允许执行过程中随机的选择下一步的计算步骤,因此使用概率算法有时会大大提高算法的效率s
优缺点:用时间上的牺牲换来了解的全面性保证。
eg:寻找指定区间的素数
#include <stdio.h>
/* n 是素数返回1 否则返回0 */
int isPrime(int n){
int i;
for(i=2; i<n;i++){
if(n%i==0) return 0;
}
return 1;
}
void printPrime(int low,int high){
int i = 0;
for(i = low; i<=high; i++){
if(isPrime(i)){
printf("%d ",i);
}
}
}
int main(void){
int low,high;
printf("please input the domain prime:\n");
printf("low:");
scanf("%d",&low);
printf("hight:");
scanf("%d",&high);
printf("The whole primes:\n");
printPrime(low,high);
return 0;
}
2.递归与分治思想
递归:直接或者间接的调用原算法本身的一种算法。
设计递归注意点:
(1) 每个递归函数必须有一个非递归定义的初始值,作为递归结束标志。
(2) 设计递归算法的时候,要解决的问题必需具有递归性。
(3) 递归算法运行效率低,时间和空间复杂度比较高,因此设计到对于一些对时间和空间要求比较高的程序,建议使用非递归算法
分治思想:解决一些规模较大的问题时,常常将问题进行分解成规模较小的同类问题,然后将小问题逐个解决,最终也就将整个大问题解决。比如折半查找。
3.贪心算法思想
所谓的贪心算法,总是在做出当前看来是最好的选择的一种方法,比如有三种硬币,面值分别为1元,5角,1角,如果给客户找2元7角,请问怎么找才能使硬币数目最少。
方案:首先找一个面值不超过2元7角的最大硬币,即1元硬币。
然后从2元7角种减去1元,得到1元7角,再找一个面值不超过1元7角的最大硬币,即1元硬币,以此类推,
我们长用的哈夫曼编码算法,最小生成树算法,求解最短路径算法都属于贪心算法思想。
eg:最优装船问题
有一批集装箱要装入一个载质量为C的货船中,每个集装箱的质量由用户自己输入,在货船的体积不限的前提下,如何装载集装箱才能尽可能多的将集装箱装入货船中。
#include <stdio.h>
#include <stdlib.h>
void sort(int w[],int t[],int n){
int i,j,temp;
int *w_temp = (int *) malloc(sizeof(int) *n);//用于排序
for(i = 0;i<n;i++){
w_temp[i] = w[i];
}
for(i = 0; i<n;i++){
t[i] = i;
}
for(i=0; i<n; i++){
for(j=i+1;j<n;j++){
if(w_temp[i]>w_temp[j]){
temp = w_temp[j];
w_temp[j] = w_temp[i];
w_temp[i] = temp;
//交换下标
temp=t[i];
t[i] = t[j];
t[j] = temp;
}
}
}
}
void loading(int x[],int w[],int c, int n){
int i;
int *t = (int *) malloc(sizeof(int) *n);//存放排序好的数组下标
sort(w,t,n);
for(i=0; i<n && w[t[i]]<=c;i++){
//上船的box标识为1
x[t[i]] = 1;
//剩余质量
c = c - w[t[i]];
}
}
int main(void){
int x[5];//存放下标,1表示已经上船
int w[5];//存放box
int c;//总质量
int i;
printf("Please input the max\n");
scanf("%d",&c);
printf("Please input the weight of five box\n");
for(i = 0; i<5;i++){
scanf("%d",&w[i]);
}
loading(x,w,c,5);
for(i=0; i<5; i++){
if(x[i]==1) {
printf("BOX:%d ",i);
}
}
return -1;
}
4.回溯法
处理规模较大的问题可以用回溯法。基本思想:在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当搜索到某一个结点时,要先判断该结点是否包含问题的解,如果包含,从该结点继续探索,如果不包含,那就说明以该结点为根结点的字树一定不包含问题的最终解,因此要跳过对该结点为根的子树的探索,逐层向其祖先结点回溯。
eg:N皇后问题,求解如何在一个N * N 的棋盘上无冲突地摆放N个皇后棋子,在任意一个皇后所在位置的水平,竖直,以及45度斜线上都不能出现出现其它皇后的棋子。
5.概率算法
概率算法允许执行过程中随机的选择下一步的计算步骤,因此使用概率算法有时会大大提高算法的效率s