您的位置:首页 > 其它

动态规划实现 01背包问题

2011-04-03 12:02 260 查看
★问题描述 给定n种物品和一背包。物品i的重量是weight[i],其价值为value[i],背包的容量为capacity。问:应该如何选择装入背包的物品(这些物品每样只有一件,要么被装入要么被留下),使得装入背包中物品的总价值最大?
★格式输入 Capacity numGoodsweight[1] value[1]weight[2] value[2]......
★格式输出 第一行1个数字,表示总最大价值。
第二行共n个数字,表示所选的物品。
★样例输入 10 5
2 6
2 3
6 5
5 4
4 6
★样例输出 15
1 2 5
★算法设计(包括算法设计过程中相关内容的说明、数据结构的选择、 算法详细描述及算法分析):
●1.设计说明:
1.1最优子结构性质:设(x1,x2,...,xn)是所给0-1背包问题的一个最优解,则(x1,x2,...,xn-1)是下列子问题的最优解。
1.2递归公式:
m(i,j)是背包容量为j,可选择前i 个物品时0-1背包问题的最优值,由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下:
m(i,j) = m(i-1,j) // 0<= j <weight[i];
max{m(i-1,j),m(i-1,j-weight[i])+value[i]} //j >= weight[i]
●2.算法设计:
●2.1数据结构:
int capacity; //背包容量
int numGoods; //物品数量
int max[MAX_NUM][MAX_CAPACITY];//记录递归中间结果
int weight[MAX_NUM]; //物品重量
int value[MAX_NUM]; //物品价值
int chose[MAX_NUM]; //记录物品是否被选中,为1则选中,为0未被选中
int maxValue; //背包中物品的最大价值
●2.2算法描述:
input(numGoods,weight,value);//读入数据
printInitData(capacity,numGoods,weight,value,max);//打印初始化后的数据
dKnap(maxValue,max,capacity,numGoods,weight,value); //求解背包问题
traceBack(chose,numGoods,capacity,max);//判断物品是否被选中
printResult(numGoods,capacity,maxValue,max,chose);//打印计算结果
//计算并保存最优子结构
for(int i = 1; i <= numGoods; i++)
{
for(int j = 1; j <= capacity; j++)
{
if(j < weight[i])
m(i,j) = m(i-1,j);
else if(j >= weight[i])
m(i,j) = max{m(i-1,j),m(i-1,j-weight[i])+value[i]};
}
}
//判断物品是否被选中
if(max[i][capacity] == max[i-1][capacity])
chose[i] = 0;
else
{
chose[i] = 1;
capacity -= weight[i];
}
●2.3算法分析
Dknap()函数的复杂度为O(nc) 其中c = capacity
traceBack()复杂度为O(n)
本算法的最坏时间复杂度为:O(nc)
最坏空间复杂度为:O(nc)
//=============================================
//dKNAP.cpp
//0/1 Knapsack problem
//动态规划
//by leo
//3.28.2011
//=============================================
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
//---------------------------------------------
const int MAX_NUM = 1000;//最大物品数
const int MAX_CAPACITY = 10000;
//最大容量
const string outFileName = "output.txt";
//输出文件名称
int capacity;            //背包容量
int numGoods;            //物品数量
int max[MAX_NUM][MAX_CAPACITY];//记录递归中间结果
int weight[MAX_NUM];     //物品重量
int value[MAX_NUM];      //物品价值
int chose[MAX_NUM];      //记录物品是否被选中,为1则选中,为0未被选中
int maxValue;            //背包中物品的最大价值
//---------------------------------------------
void input(int& numGoods,int* weight,int* value);
//读入数据
void printInitData(int capacity,int numGoods,const int* weight,const int* value,int max[][MAX_CAPACITY]);
//打印初始化后的数据
void dKnap(int& maxValue,int max[][MAX_CAPACITY],int capacity,int numGoods,const int* weight,const int* value);
//求解背包问题
void traceBack(int* chose,int numGoods,int capacity,int max[][MAX_CAPACITY]);
//判断物品是否被选中
void printMax(int numGoods,int capacity,int max[][MAX_CAPACITY]);
//打印最优值数组
void printResult(int numGoods,int capacity,int maxValue,int max[][MAX_CAPACITY],int* chose);
//打印计算结果
//---------------------------------------------
int main()
{
input(numGoods,weight,value);
printInitData(capacity,numGoods,weight,value,max);
dKnap(maxValue,max,capacity,numGoods,weight,value);
traceBack(chose,numGoods,capacity,max);
printResult(numGoods,capacity,maxValue,max,chose);
system("pause");
return 0;
}
//---------------------------------------------
//根据用户输入,读取相应文件内容并将之保存到数组中
//---------------------------------------------
void input(int& numGoods,int* weight,int* value)
{
string str;
cout << "Please input the input file name"
<< "(input_assign02_00.txt~input_assign02_01.txt):/n";
cin >> str;
ifstream fin(str.c_str());
if(!fin)
{
cout << "no such file,please check the file name!" <<endl;
exit(0);
}
fin >> capacity >> numGoods;
for(int i = 1; i <= numGoods, fin >> weight[i] >> value[i]; i++);
}
//---------------------------------------------
//打印初始化后的数据
//---------------------------------------------
void printInitData(int capacity,int numGoods,const int* weight,const int* value,int max[][MAX_CAPACITY])
{
cout << "capacity : " << capacity <<endl;
cout << "numGoods : " << numGoods <<endl;
cout << "weight  " << "value "<<endl;
for(int j = 1; j <= numGoods; j++)
cout << weight[j] << "       " << value[j] <<endl;
cout << "before caculate:/n";
printMax(numGoods,capacity,max);
}
//---------------------------------------------
//将计算所得最优值保存在数组中
//---------------------------------------------
void dKnap(int& maxValue,int max[][MAX_CAPACITY],int capacity,int numGoods,const int* weight,const int* value)
{
for(int n = 0; n <= capacity; n++)
max[0]
= 0;
for(int m = 0; m <= numGoods; m++)
max[m][0] = 0;
for(int i = 1; i <= numGoods; i++)
{
for(int j = 1; j <= capacity; j++)
{
if(j < weight[i])
max[i][j] = max[i-1][j];
else if(j >= weight[i])
{
int maxNoI = max[i-1][j];
int maxHavI = max[i-1][j-weight[i]] + value[i];
max[i][j] = maxNoI > maxHavI ? maxNoI : maxHavI;
}
}
}
maxValue = max[numGoods][capacity];
}
//---------------------------------------------
//判断物品是否被选中
//选中:chose[i] = 1,未选中:chose[i] = 0;
//---------------------------------------------
void traceBack(int* chose,int numGoods,int capacity,int max[][MAX_CAPACITY])
{
for(int i = numGoods; i > 0; i--)
{
if(max[i][capacity] == max[i-1][capacity])
chose[i] = 0;
else
{
chose[i] = 1;
capacity -= weight[i];
}
}
}
//---------------------------------------------
//打印最优值数组
//---------------------------------------------
void printMax(int numGoods,int capacity,int max[][MAX_CAPACITY])
{
for(int i = 0; i <= numGoods; i++)
{
for(int j = 0; j <= capacity; j++)
{
cout << max[i][j] << " ";
}
cout << endl;
}
}
//---------------------------------------------
//打印计算结果
//---------------------------------------------
void printResult(int numGoods,int capacity,int maxValue,int max[][MAX_CAPACITY],int* chose)
{
ofstream fout(outFileName.c_str());
cout << "after caculate:/n";
printMax(numGoods,capacity,max);
cout << "maxValue: " << maxValue <<endl;
fout << maxValue <<endl;
cout << "the Goods that be chose:/n";
for(int i = 1; i <= numGoods; i++)
{
if(chose[i] == 1)
{
cout << i << " ";
fout << i << " ";
}
}
}
//=============================================
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: