POJ 1456 Supermarket解题总结

Honor Statement:自己没有写出来,参考了网上的解答才写出来的。算法非原创,但文章内容是自己写的。

语言:C++(其实没用到多少C++里的东西)

算法思想:贪心算法。按照每个productprofit从大到小依次决定每个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类,profitdeadline为类成员,并在类里重载运算符’<’,这样就可以利用C++sort函数(#inlcude <algorithm>)进行排序了。当然,也可以自己写个compare函数(格式请度娘或谷哥之),然后在调用sort函数时当成回调函数传进去。(*1)排好序后进行第二步。设排好序后的数据对数组为productsproducts[0]profit最大的数据对。

2.定义一个长度为max_deadlin+1int型数组,记为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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值