实验内容
(1)0/1背包问题
用回溯法实现0/1背包问题的求解,问题的规模N取4,6,8,10,12…,要求随机生成物品的重量和价值,物品重量的取值范围1~10,物品价值的取值范围1~50,背包的容量C可由用户输入。
(2)奇怪的比赛
某电视台举办了低碳生活大奖赛。题目的计分规则相当奇怪:每位选手需要回答10个问题(其编号为1到10),越后面越有难度。答对的,当前分数翻倍;答错了则扣掉与题号相同的分数(选手必须回答问题,不回答按错误处理)。每位选手都有一个起步的分数为10分。某获胜选手最终得分刚好是N分,N的取值为0,10,20,…,90,100,设计回溯算法,编写程序,输出所有可能的答题情况。
实验结果
0/1背包问题
剪枝策略1:若选择该物品后重量超过背包容量,则回溯
剪枝策略2:若选择当前后的所有商品也不超出背包容量,则全部选择
剪枝策略3:对物品按照单位重量的价值进行排序
奇怪的比赛
剪枝策略1:若答错该题目后得分为负数,则不能达到指定分数,回溯
剪枝策略2:当前分数减去后面所有题目的分数仍然大于指定分数,则回溯
源代码
0/1背包问题
#include<iostream>
#include<time.h>
using namespace std;
//物品的个数
int n;
//用于记录是否存放当前物体
int in[32];
//保存最多的价值
int val;
//背包的容量
int c;
bool Bag(int m, int weight[])
{
//一直遍历m层之前的所有物体,求出其对应的重量
int allweight = 0;
for (int i = 0; i <= m; ++i)//计算出总共的重量
allweight += in[i] * weight[i];
//比较当前的物体总重量和背包的总重量关系
return allweight <= c;
}
void Band(int m, int weight[], int value[])
{
//首先确定终止条件,那就比较最大值
if (m == n)
{
int sum = 0;
for (int i = 0; i < m; i++)
sum += value[i] * in[i];
//比较最大值
if (sum > val)
val = sum;
}
else
{
//没有到达终止条件,继续向下进行递归
for (int i = 0; i < n/2; i++)
{
in[m] = i;
//判定是否满足对应约束条件
if (Bag(m, weight))//满足约束条件,继续向下进行递归的
Band(m + 1, weight, value);
}
}
}
int main()
{
int i;
clock_t start, end;
int weight[32], value[32];
srand((unsigned)time(NULL));
cout << "输入问题规模:";
cin >> n;
cout << "输入背包容量:";
cin >> c;
for (i = 0; i < n; i++)
{
weight[i] = rand() % 10 + 1;
value[i] = rand() % 50 + 1;
}
start = clock();
Band(0, weight, value);
end = clock();
cout << "物品重量为:";
for (i = 0; i < n; i++)
cout << " " << weight[i];
cout << endl;
cout << "物品价值为:";
for (i = 0; i < n; i++)
cout << " " << value[i];
cout << endl;
cout << "背包最大价值是:" << val << endl;
cout << "耗时" << double(end - start) * 1000 / CLOCKS_PER_SEC << " ms";
return 0;
}
奇怪的比赛
#include<iostream>
#include<cstring>
#include<time.h>
using namespace std;
int grade[11] = { 0 };
int ans;
int cal(int n)
{
int sum = 10;
for (int i = 1; i <= n; i++)
{
if (grade[i])
sum *= 2;
else
sum -= i;
}
return sum;
}
void slove(int ans)
{
bool is = true;
int k = 1;
while (k > 0)
{
grade[k]++;
while (cal(k) <= 0 && grade[k] < 2)
grade[k]++;
if (grade[k] < 2 && k < 11)//判断树宽度,深度
{
if (k == 10 && cal(k) == ans)
{
is = false;
for (int i = 1; i <= 10; i++)
cout << " " << grade[i];
cout << endl;
}
else
k++;
}
else
{
grade[k] = -1;
k--;
}
}
if (is)
cout << "此得分无解" << endl;
}
int main()
{
memset(grade, -1, sizeof(grade));//所有的数设置为-1
clock_t start, end;
cout << "输入最终得分:";
cin >> ans;
start = clock();
slove(ans);
end = clock();
cout << "耗时" << double(end - start) * 1000 / CLOCKS_PER_SEC << " ms";
return 0;
}
感谢大家的观看