Honor Statement:自己没有写出来,参考了网上的解答才写出来的。算法非原创,但文章内容是自己写的。
语言:C++(其实没用到多少C++里的东西)
算法思想:贪心算法。按照每个product的profit从大到小依次决定每个product在何时卖。决定的依据很简单,如果其deadline处已安排有其他的product,那么往前寻找,遇到的第一个没有安排过物品的时间点即是该货物的卖出时间。若没有找到,那么说明在其deadline前都已安排有其他物品,并且每个物品都比其价值高(因为价值高的物品先安排)。那么该货物就不能进入利润最高时的sell名单。具体步骤如下:
0.从控制台接收数据,注意在接收数据时,要统计输入的数据中最大的deadline为多少,记为max_deadline。用伪代码说明如下:
int max_deadline = -1;// Initialize
while(…){
….//接收数据
If ( the deadline you got is greater than max_maxline )
then max_deadline = the deadline you got
else do nothing
}
1.将输入的<profit, deadline>数据对按照profit由大到小排序。最好定义一个product类,profit和deadline为类成员,并在类里重载运算符’<’,这样就可以利用C++的sort函数(#inlcude <algorithm>)进行排序了。当然,也可以自己写个compare函数(格式请度娘或谷哥之),然后在调用sort函数时当成回调函数传进去。(*注1)排好序后进行第二步。设排好序后的数据对数组为products,products[0]为profit最大的数据对。
2.定义一个长度为max_deadlin+1的int型数组,记为sell。将数组初始化为零(建议用memset初始化,用法请度娘或谷哥)。
3.令i = 0;
4.若在sell数组的products[i].deadline处的数值为零,即 if ( sell[products[i].deadline] == 0 )那么令sell[products[i].deadline] = products[i].profit。若sell数组的products[i].deadline处的数值不为零,这说明该处已安排了价值更高的物品了。从大往小依次扫描sell数组下标小于products[i].deadline的各个元素,找到第一个为零的那个元素后,进入下一步。
5.若不是sell数组的0号元素,则令该元素 = products[i].profit。
6.若该组元素已处理完,进入下一步,否则i++后进入第四步。
7.若未到文件尾,则执行第0步,否则程序结束。
算法正确性的分析(非证明):profit高的物品先安排卖出。因此在高利润的货物尽可能卖出之前,低利润的货物不能卖出。
算法总结:算法在最坏的情况下时间复杂度为O(n*n),空间复杂度为O(1)。时间主要耗费在每个货物都要查找其deadline之前(含deadline)第一个为没有安排货物的时间点。最坏的情况举例:所有的货物的deadline都是max_deadline。
算法改进:可以从改进如何查找没有安排货物的时间点入手。
待解决的疑问点:
1.有的解法说可以用并查集、线段树等方法解决,能力所限,暂时不知道这些是什么。用过堆,但是思路不对,OJ说超时或错误答案。
2.算法缺少严格的证明。感觉应该可以用《Algorithm Design》里贪心算法那章的证明思路证明。
实现代码:
#include <iostream>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <functional>
#define MAX_PRODUCT 10005
using namespace std;
class Product{
public:
int deadline;
int profit;
bool operator < (const Product& rop) const {
return rop.profit < profit;
}
};
int main(){
int profit[MAX_PRODUCT];
Product* products = new Product[MAX_PRODUCT];
int sum, num,i,max_deadline,j;
string s;
while ( cin >> s ){
sum = 0;
i = 0;
max_deadline = -1;
num = atoi ( s.c_str() );
while( i < num ){
cin >> s;
products[i].profit = atoi ( s.c_str() );
cin >> s;
products[i].deadline = atoi ( s.c_str() );
if ( products[i].deadline > max_deadline )
max_deadline = products[i].deadline;
i++;
}
memset(profit,0, (max_deadline+1)*sizeof(int));
sort( products, products + num );
for( i = 0; i < num; i++ ){
if( profit[ products[i].deadline ] == 0 )
profit[ products[i].deadline ] = products[i].profit;
else{
for( j = products[i].deadline -1;;j-- )
if( profit[j] == 0 )
break;
if ( j != 0 ) profit[j] = products[i].profit;
}
}
for ( i = 1; i <= max_deadline; i++ )
sum += profit[i];
cout << sum << endl;
}
return 0;
}
*注1:有的解法说相同价值的货物应该将deadline大的先安排,但个人认为没有必要。
*注2:控制台里输入EOF的方法:Ctrl+Z,然后Enter。