买糖果(京东2016实习生真题)

题目描述
									

某糖果公司专门生产儿童糖果,它最受儿童欢迎的糖果有A1、A2两个序列,均采用盒式包装。包装好的A1类糖果体积为一个存储单位,而包装好的A2类糖果体积正好是A1类的两倍。


这两类糖果之所以广受儿童欢迎,是因为糖果中含有公司独家研发的魔幻因子。A1或A2序列中的糖果,看起来包装可能是一样的,但因为其中的魔幻因子含量不同被细分为不同的产品。


临近传统节日,公司的糖果供不应求。作为一个精明的糖果分销商,小东希望能够借此大赚一笔,于是带着现金开着货车来公司提货。货车的容量是确定的,小东希望采购的糖果能够尽可能装满货车,且糖果的魔幻因子总含量最高。只要不超出货车容量,糖果总可以装入货车中。


小东希望你能帮她解决这一问题。


输入

输入中有多组测试数据。每组测试数据的第一行有两个整数n和v,1<=n<=10^5, 1<=v<=10^9,n为可供选购糖果数量,v为货车的容量。随后n行为糖果的具体信息,第一行编号为1,第二行编号为2,以此类推,最后一行编号为n。每行包含两个整数ti和pi,1<=ti<=2, 1<=pi<=10^4,ti为糖果所属的序列,1为A1、2为A2,pi则是其中的魔幻因子含量。

样例输入

3 2

1 2

2 7

1 3


输出

对每组测试数据,先在单独的一行中输出能采购的糖果中的魔幻因子最高含量,之后在单独的行中按编号从小到大的顺序输出以空格分隔的糖果编号,若有多组糖果组合均能满足要求,输出编号最小的组。若没有糖果能够满足要求,则在第一行中输出0,第二行输出“No”。

样例输出

7

2


时间限制 C/C++语言:1000MS 其它语言:3000MS
内存限制 C/C++语言:65536KB 其它语言:589824KB


解题思路:

这是0-1背包问题,但这个比0-1背包要简单,因为物品的体积只有两种1或2。如果按照模板来定义一个大小为货车容量V的的数组,那么数组太大行不通,由于物品的体积类型比较简单,所以我们可以模拟比较过程。其中容易被人忽视的一点是:当货车容量只剩1的时候,体积为1和为2的糖果还有,一般大家认为选择体积为1的糖果(x1),那么这就错了,应为如果体积为2的糖果它的含量比已经装进货车的体积为1的糖果+即将选择的体积为1的糖果它们的含量还高。那么我们就需要用体积为2的糖果去替已经在货车里的和误认为要选的糖果(x1).这时候的结果才是最优的。


AC代码如下:

///*
//要求:1.背包中的val最大
//      2.需要知道背包中放了哪些东西 
//*/
#include<stdio.h>
#include<algorithm>
#include<queue> 
using namespace std;
struct stu{
int n,p;	
};
bool operator < (stu a,stu  b)
{  
   if(a.p==b.p){
   	 return a.n>b.n;//按n的大小,从小到大输出队
   }
   return a.p<b.p;

}
int main(){
	int n,v,i,t,sum,k,v1,v2,xn,xp,flag;
	int c[10010];
	stu ca,c1,c2,c3;
	priority_queue<stu>q1;
	priority_queue<stu>q2;
	while(scanf("%d%d",&n,&v)!=EOF){
		while(!q1.empty()) q1.pop();
    	while(!q2.empty()) q2.pop();
        flag=0;k=0;sum=0;
        xp=10010;
		for(i=1;i<=n;i++){//保存糖果信息 
			scanf("%d%d",&t,&ca.p);
		    ca.n=i;
			if(t==1){
				q1.push(ca);
		    }else{
		    	q2.push(ca);
		    }
		}
		while((q1.size()>0||q2.size()>0)&&v){//开始装糖果 ,q1,q2其中两个同时不能为空 
		    if(q1.size()>=2){//q1能出两份糖果 
		    	c1 = q1.top();
			    q1.pop();
		        c2=q1.top();
			    q1.pop();
			    v1=2;
		    }else if(q1.size()==1){//q1只能出一份糖果 
		        c1 = q1.top();
			    q1.pop();
			    v1=1;
		    }else{//q1没有糖果了 
		    	v1=0;
		    }
			if(!q2.empty()){//q2能出糖果 
				c3=q2.top();
		     	q2.pop();
			}else{
				c3.n=0;
				c3.p=0;
			}
			if(v>=2){ 
				if(v1==2){//q1能出两份糖果 
					if(c3.p>=c2.p+c1.p){//如果c3没有糖果就为0; 
					    c[k++]=c3.n;
					    sum+=c3.p;
					    q1.push(c1);
					    q1.push(c2);
					}else{
						c[k++]=c1.n;
						c[k++]=c2.n;
						if(c2.p<xp){
							xp=c2.p;
							xn=c2.n;
						}
						sum+=c1.p+c2.p;
						 if(c3.n!=0){
						 	q2.push(c3);//此时q2为空却又存进去,会发生错误,所以需要判断 
						 }
					}
					v-=2;
			    }else if(v1==1){//q1只能出一份糖果 
			    	if(c3.p>=c1.p){
			    		c[k++]=c3.n;
					    sum+=c3.p;
					    q1.push(c1);
					    //if(c1.n==0){
					    //	printf("3\n");
					    //}
			    	    v-=2;
					   }else{
					   		c[k++]=c1.n;
					   		sum+=c1.p;
					   		v-=1;
					   		if(c1.p<xp){
					   			xp=c1.p;
					   			xn=c1.n;
					   		}
					   		if(c3.n!=0){
						 	q2.push(c3);//此时q2为空却又存进去,会发生错误,所以需要判断 
						 }
					   		//if(c1.n==0){
					    //	printf("4\n");
					   // }
					   }
			       }else{//q1没有糖果了 ,又能保证q2可定有糖果 
			       	   	c[k++]=c3.n;
					    sum+=c3.p;
					    v-=2;
			       }
			 }else{ //v==1
				     if(v1&&(c1.p>c3.p||c1.p+xp>c3.p)){
				     	  c[k++]=c1.n;
				     	  sum+=c1.p;
				     	 // if(c1.n==0){
					    //	printf("6\n");
					    //}
				       }else if(c3.p>xp){
				       	  c[k++]=c3.n;
				       	  sum+=c3.p;
				       	  sum-=xp;
				       	  flag=1;
				       	  //if(c3.n==0){
					    //	printf("5\n");
					   // }
				       }
					   break; 
		    	}
		     	    
		}
		if(sum==0){
			printf("0\nNo\n");
		}else{
			printf("%d\n",sum);
			sort(c,c+k);
			int s=0;
	     	for(i=0;i<k;i++){
	     		if(flag&&c[i]==xn) continue;
	     	     if(s==0){//未输出第一个 
	     	         	printf("%d",c[i]);
	     	         	s=1;
	     	       }	
	     	     else{
	     	         printf(" %d",c[i]);
	     	     }
		   }
		   printf("\n");
	  }	
    }
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值