前些日子GBQC国的小明在凤凰古城痛痛快快地玩了两天,临走之前希望给女友带回两件不同种类的纪念品,而且小明的背包最多只能容纳总体积不超过V的物品,各个纪念品使其女友的高兴程度的增加值也不全是一样的。
现在小明想知道,对于小明有有财力购买的N个纪念品,他需要买回哪两个才能使女友的高兴程度的增加值最大呢?
输入包含多组测试数据。
对于每组测试数据,第一行包含三个整数N(1<=N<=10^5), C(1<=C<=10^4), V(1<=V<=10^4),其中N表示小明有财力购买的一共有N个纪念品,C表示市面上销售的纪念品一共可以分为C个种类,V表示小明的背包最多只能容纳体积不超过V的物品。接下来N行,每行用三个正整数i(1<=i<=C)、j(1<=j<=10^4)、k(1<=k<=10^5)描述一个可以购买的纪念品,表示这个纪念品属于第i个种类,其体积为j,如果将其买回可使女友的高兴程度增加k。
对于每组测试数据,用一行输出一个整数表示小明最多可以让女友的高兴程度增加多少。如果小明没办法带回两件不同种类的纪念品,则输出“-1”(不包括引号)。
由于数据量较大,推荐使用scanf和printf。
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1097
一开始我按背包做 超时了 很多人说优化一下就可以过了 现在判题系统坏了 等好了以后一定要试试
思路 线段树:/*
按物品种类排序,将相同种类的物品与之前按体积放入线段树的范围为0~限制体积-当前物品
体积的区间物品进行匹配,更新最优解后将该类物品全部插入线段树(按更优价值更新)。
*/
下面是 同学的代码
#include<stdio.h> #include<string.h> #include<vector> using namespace std; struct node { int w,v; }; struct tree { int l,r,M; }btree[50000]; int Max(int a,int b){return a<b?b:a;} void build(int i,int l,int r) { int mid; btree[i].l=l; btree[i].r=r; btree[i].M=0; if(l==r) return; mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); } void update(int i,int p,int v) { btree[i].M=Max(btree[i].M,v); if(btree[i].l<btree[i].r) { if(p<=btree[i<<1].r) update(i<<1,p,v); else update(i<<1|1,p,v); } } int query(int i,int p) { if(btree[i].l==btree[i].r) return btree[i].M; else { if(p<=btree[i<<1].r) return query(i<<1,p); else return Max(btree[i<<1].M,query(i<<1|1,p)); } } int main() { int n,c,v,i,k,len,sum,t; while(scanf("%d%d%d",&n,&c,&v)!=EOF) { vector<node> list[10010]; node tem; for(i=0;i<n;i++) { scanf("%d%d%d",&k,&tem.w,&tem.v); list[k].push_back(tem); } sum=-1; build(1,1,v); for(i=1;i<=c;i++) { len=list[i].size(); if(!len)continue; for(k=0;k<len;k++) { if(v-list[i][k].w>0) { t=query(1,v-list[i][k].w); if(t)sum=Max(sum,t+list[i][k].v); } } for(k=0;k<len;k++) if(list[i][k].w<=v) update(1,list[i][k].w,list[i][k].v); } printf("%d\n",sum); } return 0; }