1、回溯法
如下所示,假设当前共有三条可选择的路径,你需要一条一条走,假设走了第一条发现是死胡同,因此你返回并给这条路径做了一个标记(称为回溯)!,依次循环接着去第二条路,同样不能走,之后到第三条路可以走

N皇后问题:

当出现某一行所有位置都不能放时,需要返回上一行,对上一行的位置进行更改!
如下所示,更改Q2位置,Q3成功放置

之后放置Q4的时候,又出现没有位置可选择,依次进行回溯!
最终从更改Q1的位置开始,成功将4个皇后进行放置:

并记录以上4个的位置,一般只记录列,因为是按行依次放置的,以上结果为:

对此只要满足以下两个条件就不采用当前坐标:
(1)某两个皇后的列处于同一列:Qi列=Qj列
(2)某两个皇后之间的横坐标对应的值之间的差值的绝对值=纵坐标对应值的差值的绝对值:|Qi行-Qj行|=|Qi列-Qj列|
将方案1反转之后可得到方案2(把顺序反过来即可!!!)

a、非递归求解N皇后问题(C语言)不合法的情况下的判断
#include<math.h>
#include <stdio.h>
#define N 4
int q[N+1];//存储皇后列号
int check(int j){//传入一个j皇后与j之前的所有皇后位置进行对比看是否存在列相等或者斜对角线的情况!!!
for(int i=1;i<j;i++){
if(q[i]==q[j]||abs(i-j)==abs(q[i]-q[j])){
return 0;
}
}
return 1;
}
void queen(){//求解N皇后方案
for(int i=1;i<=N;i++){//首先将所有皇后的列赋初值
q[i]=0;
}
int answer=0;//方案数
int j=1;
while(j>=1){
q[j]=q[j]+1;
while(q[j]<=N&&!check(j)){//判断条件:列小于等于N且位置不合理的情况下才移动一格
q[j]=q[j]+1;
}
if(q[j]<=N){//当列在合理范围内时
if(j==N){//如果此时皇后已经全部正确放置则输出最终结果并打印
answer=answer+1;
printf("方案%d:",answer);
for(int i=1;i<=N;i++){
printf("%d",q[i]);
}
}else{//如果此时皇后还没有全部放置但依然在合理范围内,则继续摆放下一个皇后
j=j+1;
}
}else{//如果此时列已经超出合理范围,对当前皇后的位置进行初始化并返回上一个皇后进行回溯!!!
q[j]=0;
j=j-1;
}
}
}
int main(){
queen();
return 0;
}
b、递归求解N皇后问题 合法情况下的判断
#include <math.h>
#include <stdio.h>
#define N 4;
int q[N+1];
int answer=0;//方案数
int check(int j){
for(int i=1;i<j;i++){//!!!这里i<j!!!相当于当前皇后与之前皇后的位置要进行检查
if(q[i]==q[j]||abs(i-j)==abs(q[i]-q[j])){
return 0;
}
}
return 1;
}
void queen(int j){//递归的时候求解N皇后问题需要传参!!!
for(int i=1;i<=N;i++){
q[j]=i;//将i直接赋给列值
if(check(j)){//合法情况下的判断
if(j==N){
answer=answer+1;
printf("方案数:%d",answer);
for(int i=1;i<=N;i++){
printf("%d",q[i]);
}
}else{
queen(j+1);//调用函数进行迭代循环
}
}
}
}
int main(){
queen(1);
return 0;
}
例题一:

(1):pos[i]==pos[k]

(2):j=1
(3):!isplace(pos,j)

(4):j<N
(5):j=j-1

第二问:以上采用了 回溯的设计策略
第三问:输出为:方案1:2 4 1 3
方案2:3 1 4 2
例题二:


(1):queen[i]==queen[j]
(2):1

(3):place(j) (位置合理的情况!!!)
(4):Nqueen(j+1)
2、分治法




例题一:


(1):k<r+1
(2):arr[k]=right[j]
(3):begin<end
(4):mergeSort(arr,mid+1,end)



例题二:


(1):first+(last-first)/2+1
(2):firstSum<lastSum
(3):first+(last-first)/2 (从上面的两个getCounterfeitCoin中可以看出一个是-1,一个是+1,因此中间的就是这个数!!!)

(因为没有排序,只是查找因此只有前边的o(lgn))

例题三:

delta=(int*)malloc(sizeof(int)*(n/2)) 表示申请给这个数组存储三个int的空间

(1):k=k\2
(2):k>1

(3):data[k-dk]>data[k]
(4):data[j+dk]=t

算法是否稳定:如果现在有两个一样的数,一个是蓝色的2,一个是红色的2,如果算法在进行排序后位置没有发生变化,算法稳定,否则不稳定!!!
该算法不稳定,因为存在步长的原因,可能会导致顺序发生改变!!!


3、动态规划


0-1背包问题求解:

将以上问题分成多个子问题分别进行求解,为简化计算这里定义:从前N个物品中进行选择:

其中第0行和第0列属于边界
以下面这个为0-1背包问题为例:

按行进行求解,一般有两种情况需要进行考虑:
(1)将当前单元格同一列的上一行的数字取出作为比较的第一个参数a(如果此时单元格所对应列的值w小于单元格所对应行的物品的重量g,则直接取这个参数a放置到当前单元格中)
(2)(此时单元格对应列的重量w>=当前行i所对应物品的重量g!!!)其次计算当在背包中放置这个物品时,物品重量为g,则取前w-g列和前i-1行的物品所构成的表格中的最大值+当前行物品的价值v,与上述参数a进行比较,哪个大,这个单元格就放置哪个参数!!!
以此类推,进行求解背包问题!!!
代码求解:
#include<stdio.h>
#define N 4;//背包数量为4
#define W 5;//背包容量为5
int max(int a,int b){
return a>b?a:b;
}
int main(){
int v[]={0,2,4,5,6};//价值数组
int w[]={0,1,2,3,4};//重量数组
int f[N+1][W+1]={};//子问题求解
int i,j;
for(i=1;i<=N;i++){
for(j=1;j<=W;j++){
if(j>=w[i]){
f[i][j]=max(f[i][j-1],f[i-1][j-w[i]]+v[i]);//如果当前单元格对应的列大于当前行物品的重量,需要得出两个的最大值
}else{
f[i][j]=f[i-1][j];//否则直接是上一行同一列的值
}
}
}
printf("%d\n",f[N][W]);
return 0;
}
或者:

时间复杂度和空间复杂度一样:

例题一:


(1):c[i][j]
(2):j>=w[i]
(3):Calculate_Max_Value(v,w,i-1,j-w[i])+v[i] (这里可以借鉴上面得形式是默认不选i的情况!!!由于并没有max的函数因此需要递归)
(4):c[i][j]=temp


例题二:




(1):d[0][j]=j

(2):str1[i-1]==str2[j-1] (注意调用函数时传入的形参名是什么!!!)
(3):d[i-1][j-1]+1
(4):d[len1][len2] (返回最终的最优解!由传入的字符串长度所决定!!!)


动态规划和贪心算法的最大区别在于动态规划是全局最优解!最优方案中不一定有价值最大的物品。
而贪心算法则是以价值的大小为优先级,价值最大的一定在最终解里!!!(局部最优)