一、实验名称
贪心算法求解背包问题。
(1)问题描述:贪心法求解背包问题
(2)给定任意几组数据,利用贪心法求解背包问题的思想,选好物品使得
背包价值最大。
二、实验目的
通过上机实验,要求掌握贪心算法的问题描述、算法设计思想、程序设计。
三、实验原理
利用贪心法求解背包问题,并计算出程序运行所需要的时间。
四、实验步骤
给定一个背包,容积为c,给定n个物品{1,2……n},以及每个物品的价值vi ,体积wi,每个物品不一定要全部放入,可以是物品的一部分。求可以放入背包的物品最大价值。
①求最优解,易证本题具有最优子结构性质:
证明:(反证法)
原问题的物品集合为S,设原问题的一个最优解E(选择的物品组成的集合),E集合中一个物品是A,那么E-{A}是S-{A}在容量为C - V(A)下的最优解。
②解决问题的策略:利用贪心的思想:
首先计算每种物品单位重量的价值v[i]/w[i];
然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包。
依此策略一直地进行下去,直到背包装满为止。
五、关键代码
1.结构体
struct PerW{
double perw;//单位重量的价值
int w;
int v;
};
2.供排序用的bool函数
bool cmp(PerW p1, PerW p2){
return p1.perw>p2.perw;
}
3.贪心算法
double GreedyPack(int n,int c, vector <PerW> per){
PerW p;
int i=0;
double result=0;
sort(per.begin(),per.end(),cmp);
i=0;
while(c>0&&i<n){
p=per[i++];
if(c>p.w) result+=p.v;
else{ result+=(p.perw*c);break; }
c-=p.w; }
return result;}
4.生成不同规模样例
//生成规模为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();
六、测试结果
时间复杂度:O(nlogn)
算法的主要计算时间在于将各种物品依其单位重量的价值从大到小排序。因此,算法的计算时间上界为O(nlogn)。
七、实验心得
通过这次实验,我更为掌握了贪心算法,并且对于背包问题求解的过程和原理有了更加清楚的认识。在自己生成案例并测试运行时间的过程中,熟悉了随机化算法和运行时间的计算。
实验可改进的地方:随机化过程的加入可能是的不同规模的测试数据与理论值有偏差,可以通过每个输入规模多次测试来减小误差。
八、完整代码
#include <iostream>
#include <fstream>
#include <windows.h>
#include <time.h>
#include <vector>
#include <algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct PerW{
double perw;
int w;
int v;
};
bool cmp(PerW p1, PerW p2){
return p1.perw>p2.perw;
}
double GreedyPack(int n,int c, vector <PerW> per){
PerW p;
int i=0;
double result=0;
sort(per.begin(),per.end(),cmp);
i=0;
while(c>0&&i<n){
p=per[i++];
if(c>p.w) {
result+=p.v;
// cout<<"result= "<<result<<" p.w= "<<p.w<<" c= "<<c<<endl;
}
else{
result+=(p.perw*c);
// cout<<p.perw<<" "<<c<<" "<<result<<endl;
break;
}
c-=p.w;
}
return result;
}
int main(int argc, char** argv) {
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;
vector <PerW> per(n);
for(i=0;i<n;i++){
in>>per[i].v;
}
for(i=0;i<n;i++){
in>>per[i].w;
per[i].perw=per[i].v / per[i].w;
}
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nBegin);
double result=GreedyPack(n,c,per);
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\\2-贪心求解背包问题\\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)
plt.title('X vs Y Plot')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.grid(True)
plt.show()