问题:SupermarketPOJ - 1456
给出n个商品的价格和过期天数,问如果一天只能卖一件,问最大可能营业额
分析:
贪心策略1:
从最后一天开始往前走,每走一天,就把这一天要过期的商品纳入选择列表,每一天都把当前列表里面最贵的商品卖出,直到第一天
贪心策略2:
把所有的商品按价格从大到小排序,从最大的开始选,将其所对应的最后一天选中,如果选到当前的最大价格商品时,其所对应的最后一天已经有价格更高的商品卖出了,则再之前的日子里面选一天卖出,如果找不到这样的一天,就去尝试下一个商品,这个商品也就买不了了。这样的策略保证了每一天都卖出可以卖出的最大价值,因为假若在某一种方法里,该天卖出了一个价格更高的商品,则在我们的策略里面,这样的一个商品在之前已经考虑过了,要么截止日期在该天之前,那所谓的某种更优方法就不存在,要么就被放在了该天之后的某一天,那么我们的策略不可能比某种方案更差;
策略2里面采用并查集优化,一天如果已经有商品卖出,就和前一天合并(以前一天为根),每一次看商品可不可以卖的时候,就直接看它所在区间最后一天的根是谁就可以了,如果根已经到了头,就不能卖了
代码1(策略1):
#include<iostream> #include<algorithm> #include<cstring> #include<queue> using namespace std; priority_queue<int> que; struct prod{ int value,day; bool operator < (const prod& a){ return day>a.day; } }prods[10100]; int main(){ int n; while(cin>>n){ while(!que.empty())que.pop(); for(int i=1;i<=n;i++){ cin>>prods[i].value>>prods[i].day; } sort(prods+1,prods+1+n); int sum=0,now=prods[1].day; que.push(prods[1].value); int i=2; while(now>=1&&i>=1){ while(i>=1&&prods[i].day==now){ que.push(prods[i].value); i++; } if(!que.empty()){ sum+=que.top();//cout<<que.top()<<endl; que.pop(); } now--; } cout<<sum<<endl; } return 0; }
代码2(策略2):
#include<iostream> #include<algorithm> using namespace std; struct product{ int money,day; bool operator < (const product& c){ return money>c.money; } }pros[10020]; int fa[10020],ceng[10020]; void init(int n){ for(int i=1;i<=n;i++){ fa[i]=i;ceng[i]=0; } } int find(int i){ return fa[i]==i?i:fa[i]=find(fa[i]); } void unite(int i){ int fi=find(i),ff=find(i-1); if(fi==ff)return; fa[fi]=ff; } int main(){ int n; while(cin>>n){ init(10010); int num=0; for(int i=1;i<=n;i++){ //cout<<"hi"<<endl; cin>>pros[i].money>>pros[i].day; } sort(pros+1,pros+1+n); for(int i=1;i<=n;i++){ int d=pros[i].day,p=pros[i].money; if(find(d)!=0){ //cout<<"before fa20="<<fa[20]<<endl; unite(find(d));num+=p; //cout<<"after fa20="<<fa[20]<<endl; } } /*for(int i=1;i<=20;i++){ cout<<fa[i]<<' '; }*/ //cout<<endl; cout<<num<<endl; } return 0; }