问题A: 回溯法-子集问题
题目描述
输入一个整数n表示有n(1<=n<=20)种不同的物品,要求输出这些物品的所有可能子集(如果子集中有第i个物品,则在对应的位置上输出1,否则在对应的位置上输出0;另外子集对应的二进制数要求从小到大输出,以保证答案唯一)
输入
第1行输入一个整数
输出
后面各行依次从小到大输出子集对应的二进制数
样例输入
复制
3
样例输出
复制
0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1
#include <stdio.h>
int n;//存储物品个数
int x[21]; //当前解,0 号单元不存储有效数据
void output() {
int i;
for (i = 1; i <= n; i++) {
printf("%d ", x[i]);
}
printf("\n");
}
void backtrack(int i) { // 搜索第 i 层结点
if (i > n) { //到达叶结点考虑结束本次递归
output();
} else {
x[i] = 0;
backtrack(i + 1);
x[i] = 1;
backtrack(i + 1);
}
}
int main(void) {
scanf("%d", &n);
backtrack(1);
return 0;
}
问题B: 回溯法-01背包问题
题目描述
给定n(1<=n<=20)种物品和一背包,物品i (1≤i≤n) 的重量是wi (wi > 0),其价值为vi (vi > 0),背包的容量为c, 问应如何选择装入背包的物品,使得装入背包中物品的总价值最大? 为了方便编写限界函数,假设按照单位重量获利递减输入每个物品的重量和获利。
输入
第一行输入两个整数,分别表示n个物品和背包容量c
第二行输入n个整数,分别表示每个物品的重量
第三输入n个整数,分别表示每个物品的价值
输出
第一行输出最大价值
第二行输出最解向量的值(1表示放入背包,0表示没有放入背包)
样例输入
复制
3 10 3 4 5 4 5 6
样例输出
复制
11 0 1 1
#include <stdio.h>
int w[21]; // 存储物品重量
int v[21]; // 存储物品价值
int n; // 存储物品个数
int c; // 存储背包容量
int bestx[21]; // 最优解
int x[21]; // 当前解
int bestv; // 最优值
int cv; // 当前已经放到背包中的物品价值
int cw; // 当前已经放到背包中的物品重量
double bound(int i) { // 计算剩余物品(i:n)的上界
int cleft = c - cw; // 剩余容量
double b = 0.0; // 使用double来避免整数除法导致的精度损失
while (i <= n && w[i] <= cleft) {
cleft -= w[i];
b += v[i];
i++;
}
if (i <= n) {
b += (double)v[i] / w[i] * cleft; // 装满背包
}
return b;
}
void backtrack(int i) {
if (i > n) { // 到达叶结点,更新最优解(如果当前价值更高)
if (cv > bestv) {
bestv = cv;
for (int j = 1; j <= n; j++) {
bestx[j] = x[j];
}
}
return;
}
// 不选择第i个物品,搜索右子树
if (cv + bound(i + 1) > bestv) { // 如果限界函数认为可能有更优解
backtrack(i + 1); // 不放入第i个物品,继续搜索
}
// 选择第i个物品,搜索左子树
if (cw + w[i] <= c) { // 满足背包容量限制
x[i] = 1; // 标记为已选择
cw += w[i]; // 更新当前重量
cv += v[i]; // 更新当前价值
backtrack(i + 1); // 继续搜索
// 回溯
x[i] = 0; // 撤销选择
cw -= w[i]; // 撤销重量
cv -= v[i]; // 撤销价值
}
}
int main(void) {
scanf("%d %d", &n, &c);
for (int i = 1; i <= n; i++) {
scanf("%d", &w[i]);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &v[i]);
}
cw = 0;
cv = 0;
bestv = 0; // 初始化最优价值为0
backtrack(1);
printf("%d\n", bestv);
for (int i = 1; i <= n; i++) {
printf("%d ", bestx[i]);
}
printf("\n");
return 0;
}