算法设计与分析—回溯法
回溯概念:以深度优先的方式搜索解空间的算法成为回溯法;
回溯法算法框架分类:
1)递归回溯
2)迭代回溯
3)子集树算法框架
4)排列数算法框架
问题一,回溯法解决0-1背包问题
问题描述:
n个物品装入容量为c的背包里面,物品不可以切割,问可以装入的最大价值为多少?
input:
输入一个正整数n和一个double数c(n为物品个数,c为背包容量)
接下来n行每行输入:
物品价值 物品重量
output:
输出最大价值
input_case:
5 5
1 2
3 2
5 6
1 1
2 1
output_case:
bestPrice:6.000000
code:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<set>
using namespace std;
#define INF 9999
double bestPrice=0;//最优价格
double now_weight=0;//当前背包总重量
double now_Price=0;//当前背包总价值
double limted=0;//背包的重量限制
int put[INF]={
0};//转入为1,没装入为0
typedef struct Product{
//该结构体存放物品信息
double weight;
double value;
int index;
double prep;
}Product;
double bound(int i,Product *a,int n){
//作用:剪枝
double sur_weight=limted-now_weight;
double max_price=now_Price;
while(i<n&&a[i].weight<=sur_weight){
max_price+=a[i].value;
sur_weight-=a[i].weight;
i++;
}
if(i<n){
max_price+=a[i].prep*sur_weight;
}
return max_price;
}
void backTrack(int i,int n,Product *a){
//回溯函数
if(i>=n){
bestPrice=now_Price;
return ;
}
if(a[i].weight+now_weight<=limted){
now_weight+=a[i].weight;
now_Price+=a[i].value;
put[a[i].index]=1;
backTrack(i+1,n,a);
now_weight-=a[i].weight;
now_Price-=a[i].value;
}
if(bound(i+1,a,n)>bestPrice){
//符合条件遍历右子树
backTrack(i+1,n,a);
}
}
bool cmp_prep(Product P1,Product P2){
//对价格的比较函数 (单位价格大到小)
if(P1.prep==P2.prep){
return P1.index<P2.index;
}else{
return P1.prep>P2.prep;
}
}
int main(){
int n;
cin>>n>>limted;//输入物品个数和背包容量
Product a[n];
for(int i=0;i<n;i++){
//依次输入各个物品的价值和重量
cin>>a[i].value>>a[i].weight;
a[i].index=i+1;
}
sort(a,a+n,cmp_prep);//按照单位价格从大到小排序
backTrack(0,n,a);
printf("bestPrice:%lf\n",bestPrice);
return 0;
}
问题二,n后问题
问题描述:
对于n*n的棋盘,放置n个皇后,要求每个皇后之间不能同行,不能同列,不能同对角线,问一共有多少种方案
input:
输入一个正整数num为问题规模(num<=13)num太大就超时了!!!
output:
输出对应的解的个数
input_case:
8
output_case:
92
code:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
int cnt;
int ans[13];//打表,存放答案
int size[13];//size[i]=j;意味着i行j列放置了皇后
void dfs(int n,int N){
//深度优先搜索,递归实现
int flag;
if(n==N+1){
//递归边界
cnt++;
return ;
}
for(int i=1;i<=N;i++){
size[n]=i;
flag=1;
for(int j=1;j<n;j++){
if((abs(n-j)==abs(size[j]-i))||(size[j]==i)){
//不满足条件的情况flag为0
flag=0;
break;
}
}
if(flag){
//递归
dfs(n+1,N);
}
}
}
int main(){
for(int i=1;i<=13;i++){
cnt=0;
memset(size,0,sizeof size);
dfs(1,i);
ans[i]=cnt;
}
int num;
scanf("%d",&num);
printf("%d\n",ans[num]);
return 0;
}
注:(num<=13时各个问题的解)
规模 方案数
1 1
2 0
3 0
4 2
5 10
6 4
7 40
8 92
9 352
10 724
11 2680
12 14200
13 73712