#include<iostream>
#include"backtrack01.h"
using namespace std;
int n, c, bestp;//物品数,背包容量,最大价值
int p[100], w[100], x[100], bestx[100];//物品价值,物品重量,x[i]暂存物品的选中的情况
int num = 0;
/*
算法思想:DFS+剪枝策略
本质上是对蛮力枚举的优化,优化程度较高(在实际应用中),但其最坏情况时间复杂度仍然是Ο(2^n),但一般不会,大多数的分支都被剪掉
剪左支:背包容量限制
剪右支:贪心算法求得价值上界
*/
int main(){
bestp = 0;
cout << "背包容量:" << endl;
cin >> c;
cout << "物品数" << endl;
cin >> n;
cout << "依次输入物品质量" << endl;
for (int i = 1; i <= n; i++)
cin >> w[i];
cout << "依次输入物品价值" << endl;
for (int i = 1; i <= n; i++)
cin >> p[i];
cout << "按性价比排序:" << endl;
sort(n);//按性价比排序
for (int i = 1; i <= n; i++)
cout << p[i] << " " << w[i] << endl;
backtrack(1, 0, 0);
cout << "最大价值:" << endl << bestp << endl << "选中的物品" << endl;
for (int i = 1; i <= n; i++)
if (bestx[i] != 0)cout << i << " ";
cout << endl;
cout << "num=" << num;
return 0;
}
void backtrack(int i, int cp, int cw)//回溯算法,i为递归层数,cp:当前价值,cw:当前重量
{
int j;
if (i > n){//到叶子节点
if (cp > bestp){//大于更新bestp,bestx[]
bestp = cp;
for (int i = 0; i <= n; i++)
bestx[i] = x[i];
}
}
else{
for (j = 1; j >= 0; --j){
x[i] = j;
if (cw + x[i] * w[i] <= c){
cw += w[i] * x[i];
cp += p[i] * x[i];
//if (bound(i,cp,cw) <= bestp) break;
//右子树剪枝,右子树中有可能包含最优解时才进入右子树,
//有可能包含就是bound>bestp,价值上界大于当前最大价值,说明有可能
backtrack(i + 1, cp, cw);
cw -= w[i] * x[i];
cp -= p[i] * x[i];
num++;//记录循环次数,说明时间复杂度
}
}
}
}
int bound(int i, int cp, int cw)//对剩余物品性价比进行排序,贪心选择性价比高的,返回价值上界
{
float surplus_weight = c - cw;//剩余价值
float bound = cp;//初值
for (; i > n&&surplus_weight >= w[i]; i++)//对背包剩余空间,加入物品(按性价比优先)
{
bound += p[i];
surplus_weight -= w[i];
}
if (i <= n)//贪心算法_部分背包问题,无法装入一个,装半个
{
bound += p[i] * surplus_weight / w[i];
}
//cout <<"价值上界"<< bound;
return bound;
}
void sort(int n)//对输入的物品,按性价比排序,便于求bound
{
float* p_w = (float*)malloc(sizeof(float)*(n + 1));
for (int i = 1; i <= n; i++)//计算性价比
{
p_w[i] = p[i] * 1.0 / w[i];
//cout << p_w[i]<<" ";
}
// 9 1 2 3
for (int i = 1; i <= n + 1; i++)
{
for (int j = 1; j <= n - i; j++)
{
if (p_w[j] < p_w[j + 1])
{
swap(p, j, j + 1);
swap(w, j, j + 1);
swapf(p_w, j, j + 1);
}
}
}
}
void swap(int x[], int i, int j)
{
int price = x[i];
x[i] = x[j];
x[j] = price;
}
void swapf(float x[], int i, int j)
{
float price = x[i];
x[i] = x[j];
x[j] = price;
}
/*
50
5
15 25 27 30 5
30 44 46 50 12
8
5
3 5 1 2 2
4 5 2 1 3
1000
10
501 725 359 465 146 828 492 943 437 605
170 479 963 706 282 962 996 828 392 903
5000
50
501 725 359 465 146 828 492 943 437 605
154 383 717 896 727 539 913 300 895 812
334 665 712 869 645 758 860 742 779 36
843 107 943 649 806 730 351 102 549 624
955 841 377 309 440 324 539 83 542 116
170 479 963 706 282 962 996 828 392 903
293 422 719 448 772 870 668 36 704 323
674 142 254 548 663 38 724 530 317 191
289 41 265 447 891 371 7 394 630 85
757 967 932 945 627 538 119 930 834 640
2000
20
501 725 359 465 146 828 492 943 437 605
154 383 717 896 727 539 913 300 895 812
170 479 963 706 282 962 996 828 392 903
293 422 719 448 772 870 668 36 704 323
*/
01背包回溯
最新推荐文章于 2024-09-02 16:35:28 发布