题目大意:有n (n≤105) 个货物,分为两种,一种占空间1,一种占空间为2,每个货物都有一定的价值,有大小为v (v≤109) 的背包,如何装能够使得价值最大。
题解:该题的特殊性在于两种货物所占空间分别为1和2,背包中最终可能会填满或余1的位置。以平均价格为关键字排序,再贪心地取。如果正好装满就结束,如果还差一个位置填满,需要尝试把前面的1类型货物换成2类型货物或者在后面找一个1类型货物。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
struct node{
int t,p;
int id;
bool operator<(const node &a) const {
return (1.0*p/t)>(1.0*a.p/a.t);
}
}a[maxn];
int w[maxn];
int main(){
int n,v;
scanf("%d%d",&n,&v);
for(int i = 0;i < n;i++){
scanf("%d%d",&a[i].t,&a[i].p);
a[i].id = i+1;
}
sort(a,a+n);
//for(int i = 0;i < n;i++){
// printf("i=%d %d %d\n",a[i].id,a[i].t,a[i].p);
//}
int last = -1;
int lp = -1;
int ans = 0;
int cnt = 0;
for(int i = 0;i < n&&v;i++){
if(v == 1&&a[i].t == 2){
if(last != -1){
int tt = 0,j;
for(j = i+1;j < n;j++){
if(a[j].t == 1){
tt = a[j].p;
break;
}
}
if(last + tt> a[i].p){
w[cnt++] = a[j].id;
ans += tt;
v--;
}
else if(a[i].p > last){
w[lp] = -1;
w[cnt++] = a[i].id;
ans += a[i].p-last;
v--;
}
}
continue;
}
if(a[i].t == 1){
last = a[i].p;
lp = cnt;
}
w[cnt++] = a[i].id;
ans += a[i].p;
v -= a[i].t;
}
printf("%d\n",ans);
for(int i = 0;i < cnt;i++){
if(w[i] != -1) printf("%d%s",w[i],i == cnt-1?"\n":" ");
}
return 0;
}