题意:
现在告诉你有n个物品,背包的体积为V。
然后n行,有两种类型的物品,如果是1类型的物品,那么它的体积为1,如果是2类型的物品,那么它的体积为2。并同时告诉了我们每种物品的价值。
问你在不超过背包的容量的情况下,所能获得的背包的最大价值。并同时输出被选在背包中的物品的序号。
思路:
因为V十分大,所以肯定不能是01背包。
于是我们对每种物品的价值排序,然后优先选择价值高的。
然后有一个点我没考虑到,如果这样优先选择价值高的话,背包的体积可能会有所空出来,但是可以得之背包中空出来的体积肯定是1。
于是就分了两种情况:
1)在后面的物品中选择体积为1的加进去
2)在前面的物品中选择体积为1的删除,并在后面选择体积为2的加入到我们所选的集合中。
最后就是一个WA点,这题中还存在不合法的情况,我觉得就是那个卡了我好久的test21。。。所以我们应该初始化xx为-1,然后判断一下。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
#define maxn 100010
int vis[maxn],num[maxn];
struct node{
int t,p;
double val;
int idx,v;
}a[maxn];
bool cmp(node a,node b){
return a.val>b.val;
}
int main(){
int n,V;
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].t,&a[i].p);
if(a[i].t==1) a[i].val=a[i].p/1.0,a[i].v=1;
else a[i].val=a[i].p/2.0,a[i].v=2;
a[i].idx=i;
}
sort(a+1,a+1+n,cmp);
int res=0,ans=0,xx=-1;
for(int i=1;i<=n;i++){
if(res+a[i].v<=V){
res+=a[i].v;
ans+=a[i].p;
vis[i]=1;
}
else{
xx=i;
break;
}
}
//printf("%d\n",ans);
if(V-res>0&&xx!=-1){ //注意有一种特殊情况,当没有一种物品可以被选进去的时候,也要判断过此时的情况,即为xx!=-1
int ans1=ans,a1=0;
for(int i=xx;i<=n;i++){
if(a[i].t==1){
ans1=ans+a[i].p;
a1=i;
break;
}
}
int del=0,ans2=0,a2=0;
for(int i=xx-1;i>=1;i--){
if(a[i].t==1){
del=i;
ans2=ans-a[i].p;
bool ff=false;
for(int j=i+1;j<=n;j++){
if(a[j].t==2&&!vis[j]){
ans2+=a[j].p;
a2=j;
ff=true;
break;
}
}
if(ff) break;
}
}
if(ans1>=ans2&&ans1>ans){
ans=ans1;
vis[a1]=1;
}
else if(ans2>=ans1&&ans2>ans){
ans=ans2;
vis[del]=0;
vis[a2]=1;
}
}
printf("%d\n",ans);
int t=0;
for(int i=1;i<=n;i++){
if(vis[i]){
num[t++]=a[i].idx;
}
}
for(int i=0;i<t;i++){
printf("%d%c",num[i],i==t-1?'\n':' ');
}
}
/*
6 4
1 10
1 9
2 8
2 7
1 5
1 4
*/