一、实验名称
用动态规划法求解 0-1 背包问题;
(1)问题描述:动态规划法求解 0-1 背包问题
(2)给定任意几组数据,利用动态规划法求解 0-1 背包问题的思想,选好物
品使得背包价值最大。
二、实验目的
通过上机实验,要求掌握动态规划算法的问题描述、算法设计思想、程序设
计。
三、实验原理
利用动态规划法求解 0-1 背包问题,并计算出程序运行所需要的时间。
四、实验步骤
给定一个背包,容量为c, 给定n件物品{1,2……n},第 i 件物品的体积为 wi , 价值为 vi, 现在求一种方案,将价值尽可能大的物品装入背包。
①求最优解,易证本题的最优子结构性质为:
t ( i, j ) = max{ vi + t (i-1, j-wi),t(i-1, j) } ,
t(i,j) 表示前 i 件物品放入容量为 j 的背包的最大价值。
证明:(反证法)
假设规模为n的最优解S,它包含的子问题E的解不是n-1规模中最优的:
即存在E'>E,那么S=E+vn(如果选取了n的话)<E'+vn 因此S不是原问题的最优解,矛盾。
②解决问题的策略:利用动态规划的思想,解决问题的规模从小到大,自底向上,利用状态转移方程得到原问题的最优解。
五、关键代码
1.动规求解:
int fun(int n,int m,vector<int> w,vector<int> v,vector<vector<int> >& f)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j<w[i])
f[i][j]=f[i-1][j];
else{
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
// cout<<"i="<<i<<"\tj="<<j<<endl;
// cout<<"f[i-1][j]="<<f[i-1][j]<<"\tf[i-1][j-w[i]]+v[i]="<<f[i-1][j-w[i]]+v[i]<<"\tf[i][j]="<<f[i][j]<<endl<<endl;
}
}
}
return f[n][m];
}
2.生成不同规模样例:
cout<<"请输入数据规模n:"<<endl;
int n,c;
cin>>n;
ofstream out("input1.txt");
out<<n<<'\n';
srand((unsigned)time(NULL));
// c
int a=0,b=100;//因为要建成的数组为f[n+1][c+1],所以c如果不做限制的话,这个数组会很大,一开始没做限制时,即使我设置和输入规模n为1,也会运行很长时间。
out<< (rand() % (b-a))+ a + 1<<'\n';
// v数组
for(int i=0;i<n;i++){
out<<rand()<<' ';
if((i+1)%10==0) out<<'\n';
}
out<<'\n';
// w数组
for(int i=0;i<n;i++){
//相应于上面的受限制的c,在这里对w也做相同限制。
out<< (rand() % (b-a))+ a + 1<<' ';
if((i+1)%10==0) out<<'\n';
}
out.close();
3.对实参的部分初始化:
vector<int> w(n+1),v(n+1);
v[0]=0;//对v,w的第0个元素赋值为0
w[0]=0;
vector<vector<int> > f(n+1, vector<int>(c+1));
for(int i=0;i<=n;i++) f[i][0]=0;//对f的第0列、第0行赋值0
for(int j=0;j<=c;j++) f[0][j]=0;
六、测试结果
时间复杂度:O(nc)
利用动态规划解决此问题的效率即是填写此张表的效率,为O(nc),
用到二维数组存储子问题的解,所以动态规划的空间效率为O(n*c);
七、实验心得
通过这次实验,我更为掌握了动态规划算法,并且自己生成案例并测试运行时间的过程中,熟悉了随机化算法和运行时间的计算。
实验可改进的地方:随机化过程的加入可能是的不同规模的测试数据与理论值有偏差,可以通过每个输入规模多次测试来减小误差。
八、完整代码
#include <iostream>
#include <fstream>
#include <windows.h>
#include <time.h>
#include <vector>
using namespace std;
int fun(int n,int m,vector<int> w,vector<int> v,vector<vector<int> >& f)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j<w[i])
f[i][j]=f[i-1][j];
else{
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
}
}
}
return f[n][m];
}
void traceback(int n,int c,vector<int> w,vector<vector<int> >& f,vector<int> &x)
{
for(int i=n;i>1;i--)
{
if(f[i][c]==f[i-1][c])
x[i]=0;
else
{
x[i]=1;
c-=w[i];
}
}
x[1]=(f[1][c]>0)?1:0;
}
int main(){
ofstream out1("output.txt");
while(1){
//生成规模为n的随机数
cout<<"请输入数据规模n:"<<endl;
int n,c;
cin>>n;
ofstream out("input1.txt");
out<<n<<'\n';
srand((unsigned)time(NULL));
// c (a,b]
int a=0,b=100;
out<< (rand() % (b-a))+ a + 1<<'\n';
// v数组
for(int i=0;i<n;i++){
out<<rand()<<' ';
if((i+1)%10==0) out<<'\n';
}
out<<'\n';
// w数组 (a,b]
for(int i=0;i<n;i++){
out<< (rand() % (b-a))+ a + 1<<' ';
if((i+1)%10==0) out<<'\n';
}
out.close();
int i,maxi,mini;
LARGE_INTEGER nFreq,nBegin,nEnd;
double time;
ifstream in("input1.txt");
in>>n>>c;
// cout<<"n= "<<n<<" ;c= "<<c<<endl;
vector<int> w(n+1),v(n+1);
for(i=1;i<=n;i++){
in>>v[i];
// cout<<v[i]<<" ";
}
// cout<<endl;
for(i=1;i<=n;i++){
in>>w[i];
// cout<<w[i]<<" ";
}
// cout<<endl;
v[0]=0;
w[0]=0;
vector<vector<int> > f(n+1, vector<int>(c+1));
for(int i=0;i<=n;i++) f[i][0]=0;
for(int j=0;j<=c;j++) f[0][j]=0;
// for(int i=1;i<=n;i++){
// for(int j=1;j<=c;j++){
// cout<<f[i][j]<<" ";
// }
// cout<<endl;
// }
// cout<<endl;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nBegin);
int result=fun(n,c,w,v,f);
// cout<<"物品选择情况:"<<endl;
// vector<int> x(n+1);
// traceback(n,m,w,f,x);
// for(int i=1;i<=n;i++)
// cout<<x[i]<<"\t";
QueryPerformanceCounter(&nEnd);
time=(double)(nEnd.QuadPart-nBegin.QuadPart)/(double)nFreq.QuadPart;
// cout<<"结果:"<<result<<"\n查询时间:"<<time<<endl<<endl;
out1<<n<<' '<<time<<endl;
in.close();
}
out1.close();
return 0;
}
九、绘图代码
import matplotlib.pyplot as plt
# 读取txt文件,假设文件名为data.txt
file_path = 'F:\\3-CourseMaterials\\3-1\\3-算法设计与分析\实验\lab2\\1-code\\1-动规求解0-1背包问题\\output.txt'
# 存储x和y的列表
x_values = []
y_values = []
# 读取文件并提取数据
with open(file_path, 'r') as file:
for line in file:
# 假设数据以空格或逗号分隔
x, y = map(float, line.strip().split())
x_values.append(x)
y_values.append(y)
print(x_values)
print(y_values)
# 绘制图形
plt.plot(x_values, y_values, marker='o', linestyle='-')
plt.title('X vs Y Plot')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.grid(True)
plt.show()