掌握回溯法的基本思想和解决问题的基本步骤,认识回溯法和动态规划、贪心选择的联系与区别,对比解决同一问题的三种算法设计策略的优缺点。
用c++语言实现递归回溯回溯和迭代回溯解决0-1背包问题,分析时间复杂性,体会回溯法解决问题的基本思路和步骤。
见附件一
实验步骤、特点
重要源代码(流操作的部分要醒目的提示并注释)
见附件二
遇到的问题,及解决方案
/*
* Algorithm experiment 7 0-1背包问题的回溯算法递归实现
*/
#include "bits/stdc++.h"
#define maxn 10000
using namespace std;
int mn[maxn] = {0};
int mnn[maxn] = {0};
int perw[maxn] = {0};
int maxw = 0;
template<class Typew, class Typep>
class Knap {
public:
// friend Typep Knapsack(Typep *, Typew *, Typew, int);
public:
Typep Bound(int i);
void Backtrack(int i);
Typew c;//背包容量
int n;//物品数
Typew *w;//物品重量数组
Typep *p;//物品价值数组
Typew cw;//当前重量
Typep cp;//当前价值
Typep bestp;//当前最优价值
};
template<class Typew, class Typep>
void Knap<Typew, Typep>::Backtrack(int i) {
if (i > n) {//到达叶节点
bestp = cp;
maxw = cw;
memcpy(mnn, mn, (n + 1) * sizeof(int));
return;
}
if (cw + w[i] <= c) {//进入左子树
mn[i] = 1;
cw += w[i];
cp += p[i];
Backtrack(i + 1);
mn[i] = 0;
cw -= w[i];
cp -= p[i];
}
if (Bound(i + 1) > bestp) {//进入右子树
mn[i] = 0;
Backtrack(i + 1);
}
}
template<class Typew, class Typep>
Typep Knap<Typew, Typep>::Bound(int i) {//计算上界
Typew cleft = c - cw;//剩余容量
Typep b = cp;
while (i <= n && w[i] <= cleft) {//以物品单位重量价值递减序装入背包
cleft -= w[i];
b += p[i];
i++;
}
if (i < n) //装满背包
b += p[i] * cleft / w[i];
return b;
}
class Object {
public:
// friend int Knapsack(int *, int *, int, int);
public:
int operator<=(Object a) const { return (d >= a.d); }
public:
int ID;
double d;
};
bool tmp(Object a, Object b) {
return a.operator<=(b);
}
void Sort(Object *pObject, int n);
template<class Typew, class Typep>
Typep Knapsack(Typep p[], Typew w[], Typew c, int n) {//初始化
Typew W = 0;
Typep P = 0;
Object *Q = new Object[n];
for (int i = 1; i <= n; i++) {
Q[i - 1].ID = i;
Q[i - 1].d = 1.0 * p[i] / w[i];
P += p[i];
W += w[i];
}
if (W < c)//装入所有物品
return P;
Sort(Q, n);//依物品单位重量价值排序
cout << endl;
Knap<Typew, Typep> K;
K.p = new Typep[n + 1];
K.w = new Typew[n + 1];
for (int i = 1; i <= n; i++) {
K.p[i] = p[Q[i - 1].ID];
K.w[i] = w[Q[i - 1].ID];
}
K.cp = 0;
K.cw = 0;
K.c = c;
K.n = n;
K.bestp = 0;
K.Backtrack(1);//回溯搜索
cout << "按单位重量价值排序:";
for (int i = 1; i <= n; i++) {
cout << Q[i - 1].ID << " ";
perw[Q[i - 1].ID] = mnn[i];
}
cout<<endl;
delete[] Q;
delete[] K.w;
delete[] K.p;
return K.bestp;
}
void Sort(Object *pObject, int n) {
sort(pObject, pObject + n, tmp);
}
int main() {
int c, n;
cout << "请输入物品数量n:";
cin >> n;
cout << "请输入背包容量c:";
cin >> c;
int *w = new int[n];
cout << "请依次输入物品重量w:" << endl;
for (int i = 1; i <= n; i++) {
printf("w[%d]:", i);
cin >> w[i];
}
int *p = new int[n];
cout << "请依次输入物品价值p:" << endl;
for (int i = 1; i <= n; i++) {
printf("p[%d]:", i);
cin >> p[i];
}
int bestp = Knapsack(p, w, c, n);
cout << "各物品装载情况:";
for (int i = 1; i <= n; i++) {
cout <<i<<"号物品 ";
}
cout << endl;
cout << "各物品装载情况:";
for (int i = 1; i <= n; i++) {
cout<<setw(6)<<left << perw[i]<<" ";
}
cout << endl;
cout << "能够装载的最大价值为:";
cout << bestp << endl;
cout << "能够装载的最大重量为:";
cout << maxw << endl;
return 0;
}
/*
7
150
35
30
60
50
40
10
25
10
40
30
50
35
40
30
*/
/*
* Algorithm experiment 7 0-1背包问题的回溯算法非递归实现
*/
#include "bits/stdc++.h"
#define maxn 10000
using namespace std;
int mn[maxn] = {0};
int mnn[maxn] = {0};
int perw[maxn] = {0};
int cnt[maxn] = {0};
int maxw = 0;
template<class Typew, class Typep>
class Knap {
public:
// friend Typep Knapsack(Typep *, Typew *, Typew, int);
public:
Typep Bound(int i);
void Backtrack(int i);
Typew c;//背包容量
int n;//物品数
Typew *w;//物品重量数组
Typep *p;//物品价值数组
Typew cw;//当前重量
Typep cp;//当前价值
Typep bestp;//当前最优价值
};
template<class Typew, class Typep>
void Knap<Typew, Typep>::Backtrack(int i) {
while (i >= 1) {
if (cnt[i] <= 1) {
for (int j = cnt[i]; j <= 1; j++) {
if (i > n) {
bestp = cp;
maxw = cw;
memcpy(mnn, mn, (n + 1) * sizeof(int));
i--;
}
int child = 1 - cnt[i];
if (child) {
if (cw + w[i] <= c) {//进入左子树
mn[i] = 1;
cw += w[i];
cp += p[i];
cnt[i]++;
i++;
} else
cnt[i]++;
} else {
if (Bound(i + 1) > bestp) {//进入右子树
mn[i] = 0;
cnt[i]++;
i++;
} else
cnt[i]++;
}
}
} else {
cnt[i] = 0;
i--;
}
}
}
template<class Typew, class Typep>
Typep Knap<Typew, Typep>::Bound(int i) {//计算上界
Typew cleft = c - cw;
Typep b = cp;
while (i <= n && w[i] <= cleft) {//以物品单位重量价值递减序装入背包
cleft -= w[i];
b += p[i];
i++;
}
if (i < n) //装满背包
b += p[i] * cleft / w[i];
return b;
}
class Object {
public:
// friend int Knapsack(int *, int *, int, int);
public:
int operator<=(Object a) const { return (d >= a.d); }
public:
int ID;
double d;
};
bool tmp(Object a, Object b) {
return a.operator<=(b);
}
void Sort(Object *pObject, int n);
template<class Typew, class Typep>
Typep Knapsack(Typep p[], Typew w[], Typew c, int n) {
Typew W = 0;
Typep P = 0;
Object *Q = new Object[n];
for (int i = 1; i <= n; i++) {
Q[i - 1].ID = i;
Q[i - 1].d = 1.0 * p[i] / w[i];
P += p[i];
W += w[i];
}
if (W < c) //装入所有物品
return P;
Sort(Q, n); //依物品单位重量价值排序
cout << endl;
Knap<Typew, Typep> K;
K.p = new Typep[n + 1];
K.w = new Typew[n + 1];
for (int i = 1; i <= n; i++) {
K.p[i] = p[Q[i - 1].ID];
K.w[i] = w[Q[i - 1].ID];
}
K.cp = 0;
K.cw = 0;
K.c = c;
K.n = n;
K.bestp = 0;
K.Backtrack(1); //回溯搜索
cout << "按单位重量价值排序:";
for (int i = 1; i <= n; i++) {
cout << Q[i - 1].ID << " ";
perw[Q[i - 1].ID] = mnn[i];
}
cout << endl;
delete[] Q;
delete[] K.w;
delete[] K.p;
return K.bestp;
}
void Sort(Object *pObject, int n) {
sort(pObject, pObject + n, tmp);
}
int main() {
int c, n;
cout << "请输入物品数量n:";
cin >> n;
cout << "请输入背包容量c:";
cin >> c;
int *w = new int[n];
cout << "请依次输入物品重量w:" << endl;
for (int i = 1; i <= n; i++) {
printf("w[%d]:", i);
cin >> w[i];
}
int *p = new int[n];
cout << "请依次输入物品价值p:" << endl;
for (int i = 1; i <= n; i++) {
printf("p[%d]:", i);
cin >> p[i];
}
int bestp = Knapsack(p, w, c, n);
cout << "各物品装载情况:";
for (int i = 1; i <= n; i++) {
cout << i << "号物品 ";
}
cout << endl;
cout << "各物品装载情况:";
for (int i = 1; i <= n; i++) {
cout << setw(6) << left << perw[i] << " ";
}
cout << endl;
cout << "能够装载的最大价值为:";
cout << bestp << endl;
cout << "能够装载的最大重量为:";
cout << maxw << endl;
return 0;
}
/*
7
150
35
30
60
50
40
10
25
10
40
30
50
35
40
30
*/