最优装载问题
Description
有一批集装箱要装上一艘载重量为C的轮船。其中集装箱i的重量为wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。
Input
输入的第一个为测试样例的个数T,接下来有T个测试样例。每个测试样例的第一行是一个非负整数n( n ≤ 1000 )和一个非负整数C( C ≤ 10000 ),分别表示集装箱的个数以及轮船的载重量。接下来有n行,每行一个非负数,表示每个集装箱的重量。
Output
对应每个测试样例输出一行,格式为"Case #: D V",其中’#'表示第几个测试样例(从1开始计),D为轮船可以装载的集装箱数量的最大值,V为满足D最大时轮船的实际载重量。
最优装载可以用贪心算法求解。
贪心算法:
一般具有两个重要性质:贪心选择性质和最优子结构性质
贪心选择性质:所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解
最优子结构:当一个问题的最优解包括其子问题的最优解时,具有最优子结构。
代码(未测试)
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
void _swap( int a[], int i, int j )
{
a[i] = a[i]^a[j];
a[j] = a[i]^a[j];
a[i] = a[i]^a[j];
}
int random_position( int a[], int left, int right )
{
srand((unsigned)time(NULL));
int position = rand()%( right - left + 1) + left;
int key = a[position];
while( left < right )
{
while( left < right && a[left] < key ){ left++;}
while( left < right && a[right] > key ){right--;}
_swap(a, left, right);
}
a[left] = key;
return left;
}
void qsort(int a[], int left, int right)
{
if( left >= right )
return ;
int position = random_position(a, left, right);
qsort( a, left, position-1 );
qsort( a, position+1, right );
}
int main()
{
int t,n,c;
scanf("%d", &t);
for( int i = 1; i <= t; i++ )
{
scanf("%d%d", &n, &c);
int a[n];
for( int k = 0; k < n; k++ )
{
scanf("%d", &a[k]);
}
// sort(a, a+n);
qsort(a, 0, n-1);
int kk = 0, ans = 0;
int after_c = c;
while(a[kk] <= after_c)
{
ans++;
after_c-=a[kk++];
}
printf("Case %d: %d %d\n", i, kk, c - after_c);
}
return 0;
}
实验课用
//#include "stdafx.h"
#include <iostream>
using namespace std;
const int N = 4;
/*
template <class Type>
void Swap(Type &x,Type &y);
template<class Type>
void Loading(int x[], Type w[], Type c, int n);
template<class Type>
void SelectSort(Type w[],int *t,int n);
*/
/*
int main()
{
float c = 70;
float w[] = {0,20,10,26,15};//下标从1开始
int x[N+1];
int i;
cout<<"轮船载重为:"<<c<<endl;
cout<<"待装物品的重量分别为:"<<endl;
for(i=1; i<=N; i++)
{
cout<<w[i]<<" ";
}
cout<<endl;
Loading(x,w,c,N);
cout<<"贪心选择结果为:"<<endl;
for( i=1; i<=N; i++)
{
cout<<x[i]<<" ";
}
cout<<endl;
return 0;
}
*/
template<class Type>
void Loading(int x[],Type w[], Type c, int n)
{
int i;
int *t = new int [n+1];//存储排完序后w[]的原始索引
SelectSort(w, t, n);
for(i=1; i<=n; i++)
{
x[i] = 0;//初始化数组x[]
}
for( i=1; i<=n && w[t[i]]<=c; i++)
{
x[t[i]] = 1;
c -= w[t[i]];
}
}
template<class Type>
void SelectSort(Type w[],int *t,int n)
{
Type tempArray[N+1],temp;
memcpy(tempArray,w,(n+1)*sizeof(Type));//将w拷贝到临时数组tempArray中
int min;
int i,j;
for(i=1;i<=n;i++)
{
t[i] = i;
}
for(i=1;i<n;i++)
{
min=i;
for( j=i+1;j<=n;j++)
{
if(tempArray[min]>tempArray[j])
{
min=j;
}
}
Swap(tempArray[i],tempArray[min]);
Swap(t[i],t[min]);
}
}
template <class Type>
void Swap(Type &x,Type &y)
{
Type temp = x;
x = y;
y = temp;
}
//new
int main()
{
float c = 70;
float w[] = {0,20,10,26,15};//下标从1开始
int x[N+1];
int i;
cout<<"轮船载重为:"<<c<<endl;
cout<<"待装物品的重量分别为:"<<endl;
for(i=1; i<=N; i++)
{
cout<<w[i]<<" ";
}
cout<<endl;
Loading(x,w,c,N);
cout<<"贪心选择结果为:"<<endl;
for( i=1; i<=N; i++)
{
cout<<x[i]<<" ";
}
cout<<endl;
return 0;
}
问题描述:有一批集装箱要装上一艘载重量为c的轮船。其中集装箱i的重量为Wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。
最优子结构性质:设(x1,x2,……xn)是最优装载问题的满足贪心选择性质的最优解,则易知,x1=1,(x2,x3,……xn)是轮船载重量为c-w1,待装船集装箱为{2,3,……n}时相应最优装载问题的最优解。因此,最优装载问题具有最优子结构性质。
求解过程:最优装载问题可用贪心算法求解。采用重量最轻者先装的贪心选择策略,可产生最优装载问题的最优解。具体代码如下:
算法loading的主要计算量在于将集装箱依其重量从小到大排序,故算法所需的计算时间为 O(nlogn)。运行结果如下: