装载问题(0-1背包问题)
1、问题
2、解析
思路:轻者先装,直到再装任何集装箱将使轮船载重量超过C时停止。
-
定理:对于任何正整数k,算法(轻者先装)对k个集装箱的实例得到最优解。
证明: -
数学归纳法:K=1,只有一个集装箱,其重量小于C。任何装法都只有一种方式,因此都是最优解,所以轻者先装也是最优解。
-
假设归纳:假设算法对于规模为K的输入都能得到最优解。
考虑规模为k+1的输入,N={1,2,…,k+1},W={w1,w2,…,w(k+1)}是集装箱的重量,w1<=w2<=…<=w(k+1). -
从N中拿掉最轻的集装箱,得到k规模的输入:
N’=N-{1}={2,3,…,K+1}
W’=W-{w1}
C’=C-w1
根据归纳假设,对于k个输入,N’,W’,C’的最优解为I’,即I’为N’,不含I的最优解令I=I’∪{1}
那么I必然是N的最优解,也是N,W,C的解 -
反证法证明I必然是N的最优解:
假设I不是N的最优解 -
构建最优解1*(N,含1):假设I不是N的最优解。则必然存在最优解I*,如果I中没有1,用1替代I中的第一个集装箱标号得到的解也是最优解(个数不变,因此也是最优解),使得I为包含1的关于N的最优解且|I|>|I|。
-
构建最优解I*’(N’,不含1):因为I为包含1的关于N的最优解,==构建的I’=I*-{1}是不包含1的最优解(证明如下)==,即关于N’、W’、C’的最优解(N’、W’、C’不包含1)
- 构建的I*’=I*-{1}是不包含1的最优解(待证明)
反证法:如果I*‘=I*-(1}不是不包含1的最优解,那么存在最优解I*’’(N’,不含1),使得|I*’|<|I*’’|,
即|I*’+{1}<|I*’’+{1}),与I*’+{1}=I为最优矛盾,因此I’=I*-{1}是不包含1的最优解。 -
构建的最优解I*’与归纳假设的最优解I’比较:由|I*|>|I|得,|I*’|=|I*-{1}>|I-{1}|=|I’|,与I’的最优性矛盾(最优解I*-{1}大于最优解I’)。
3、设计
#include <iostream>
using namespace std;
const int n=100;
int t,weight1,weight2,weight[n];
int currentw,bestw,restw;
int result[n],bestresult[n];
int i;
void Back(int &i)
{
while(i>1&&result[i]==0)
{
--i;
}
if(result[i]==1)
{
result[i] = 0;
currentw =currentw+ weight[i];
i =i+1;
}
}
void Loading(int weight[])
{
while(i<=t)
{
if(currentw-weight[i]>=0)
{
currentw =currentw- weight[i];
result[i] = 1;
i =i+1;
}
else
{
result[i] = 0;
i =i+1;
}
}
if(currentw<bestw)
{
bestw = currentw;
for(i=1;i<=t;i++)
bestresult[i]=result[i];
}
Back(i);
if(i==1)
{
cout<<"第一艘轮船:"<<endl;
for(i=1;i<=t;i++)
if(bestresult[i])
cout<<i<<" ";
cout << endl;
cout<<"第二艘轮船:"<<endl;
for(i=1;i<=t;i++)
if(0==bestresult[i])
cout<<i<<" ";
return;
}
else
Loading(weight);
}
int main()
{
i = 1;
cout << "请输入集装箱的个数:";
cin >> t;
cout << "请输入第1艘和第2艘轮船的载重:";
cin >> weight1>>weight2;
cout << "请依次输入货物的重量"<<endl;
currentw = weight1;
bestw = weight1;
weight[0] = 0;
for(i=1;i<=t;i++)
{
cin>>weight[i];
restw=restw+weight[i];
}
i = 1;
Loading(weight);
return 0;
}
/*
7
152 130
90 80 40 30 20 12 10
*/
4、分析
时间复杂度:O(nlogn)