题目大意:
有n个物品放入体积为v的背包内,问正好放满n时的最小物品数量
在这个数量的基础上求
a.体积平均最小
b.体积中位数最小
c.相同体积出现的次数最大值最小
d.最大体积减去最小体积值最小
题解:
背包四合一,四个问题分开求解。
a.直接放背包维护最小值即可。
b.正反各放一遍背包,记录放进每一个时候背包的形态。放到x则将1放到x与n放到x+1的背包合并,查询是否能构成答案,并且从1放到x背包里面的物品数量大于等于n放到x+1背包里的物品数量即可。
c.直接按照体积数量一轮一轮放入,构成答案时的数量即是答案。
d.排序后从大到小放入,当能构成答案时更新ans,并且从背包中删除最小元素。用两个栈维护一下即可。
附代码,复杂度O(n^2),样例见代码后注释
#include
using namespace std;
int lim;
int f[5001];
int f1[5001],f2[5001];
int fx1[5101][5101];
int fx2[5101][5101];
int val[5001],vx[5001];
int sx[5001],s1[5001],s2[5001];
int n,v;
inline int getb()
{
memset(fx1,-1,sizeof(fx1));
memset(fx2,-1,sizeof(fx2));
fx1[0][0]=0;
fx2[0][0]=0;
int i,j;
for(i=1;i<=n;i++)
{
fx1[i][0]=0;
for(j=v;j>=1;j--)
{
if(val[i]<=j&&fx1[i-1][j-val[i]]!=-1)
{
if(fx1[i][j]!=-1)
fx1[i][j]=min(fx1[i][j],fx1[i-1][j-val[i]]+1);
else
fx1[i][j]=fx1[i-1][j-val[i]]+1;
}
if(fx1[i-1][j]!=-1)
{
if(fx1[i][j]!=-1)
fx1[i][j]=min(fx1[i][j],fx1[i-1][j]);
else
fx1[i][j]=fx1[i-1][j];
}
}
}
fx2[n+1][0]=0;
for(i=n;i>=1;i--)
{
fx2[i][0]=0;
for(j=v;j>=1;j--)
{
if(val[i]<=j&&fx2[i+1][j-val[i]]!=-1)
{
if(fx2[i][j]!=-1)
fx2[i][j]=min(fx2[i][j],fx2[i+1][j-val[i]]+1);
else
fx2[i][j]=fx2[i+1][j-val[i]]+1;
}
if(fx2[i+1][j]!=-1)
{
if(fx2[i][j]!=-1)
fx2[i][j]=min(fx2[i][j],fx2[i+1][j]);
else
fx2[i][j]=fx2[i+1][j];
}
}
}
for(i=1;i<=n;i++)
{
for(j=0;j<=v;j++)
if(fx1[i][j]+fx2[i+1][v-j]==lim&&fx1[i][j]>=fx2[i+1][v-j]&&fx1[i][j]!=-1&&fx2[i+1][v-j]!=-1)
return val[i];
}
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
scanf("%d%d",&n,&v);
int i,j,k;
for(i=1;i<=n;i++)
scanf("%d",&val[i]);
sort(val+1,val+1+n);
memset(f,127/3,sizeof(f));
f[0]=0;
for(i=1;i<=n;i++)
{
for(j=v;j>=val[i];j--)
{
if(f[j-val[i]]!=-1)
f[j]=min(f[j],f[j-val[i]]+1);
}
}
if(f[v]>n)
{
printf("-1\n");
return 0;
}
printf("%.9f ",(double)v/(double)f[v]);
lim=f[v];
/* int l=1,r=n;
while(l<=r)
{
int mid=(l+r)/2;
if(check(val[mid]))
r=mid-1;
else
l=mid+1;
}*/
//printf("%d ",val[l]);
printf("%d ",getb());
int tot=1;
vx[tot]=val[1];
sx[tot]=1;
for(i=2;i<=n;i++)
{
if(val[i]!=val[i-1])
{
tot++;
vx[tot]=val[i];
}
sx[tot]++;
}
memset(f,-1,sizeof(f));
f[0]=0;
int ans=0;
while(f[v]!=lim)
{
ans++;
for(i=1;i<=tot;i++)
{
if(!sx[i])
continue;
sx[i]--;
for(j=v;j>=vx[i];j--)
{
if(f[j-vx[i]]!=-1)
{
if(f[j]!=-1)
f[j]=min(f[j-vx[i]]+1,f[j]);
else
f[j]=f[j-vx[i]]+1;
}
}
}
}
printf("%d ",ans);
int d1=0,d2=0;
memset(fx1,-1,sizeof(fx1));
memset(fx2,-1,sizeof(fx2));
fx1[0][0]=fx2[0][0]=0;
ans=10000;
for(i=1;i<=n;i++)
{
d2++;
s2[d2]=i;
for(j=1;j<=v;j++)
fx2[d2][j]=-1;
fx2[d2][0]=0;
for(j=v;j>=1;j--)
{
if(val[s2[d2]]<=j&&fx2[d2-1][j-val[s2[d2]]]!=-1)
{
if(fx2[d2][j]!=-1)
fx2[d2][j]=min(fx2[d2][j],fx2[d2-1][j-val[s2[d2]]]+1);
else
fx2[d2][j]=fx2[d2-1][j-val[s2[d2]]]+1;
}
if(fx2[d2-1][j]!=-1)
{
if(fx2[d2][j]!=-1)
fx2[d2][j]=min(fx2[d2][j],fx2[d2-1][j]);
else
fx2[d2][j]=fx2[d2-1][j];
}
}
bool flag=false;
for(j=0;j<=v;j++)
{
if(fx2[d2][j]+fx1[d1][v-j]==lim&&fx2[d2][j]!=-1&&fx1[d1][v-j]!=-1)
flag=true;
}
while(flag)
{
if(d1!=0)
{
ans=min(ans,val[i]-val[s1[d1]]);
d1--;
}
else
{
ans=min(ans,val[i]-val[s2[1]]);
for(k=d2;k>=1;k--)
{
d1++;
s1[d1]=s2[k];
for(j=1;j<=v;j++)
fx1[d1][j]=-1;
fx1[d1][0]=0;
for(j=v;j>=1;j--)
{
if(val[s1[d1]]<=j&&fx1[d1-1][j-val[s1[d1]]]!=-1)
{
if(fx1[d1][j]!=-1)
fx1[d1][j]=min(fx1[d1][j],fx1[d1-1][j-val[s1[d1]]]+1);
else
fx1[d1][j]=fx1[d1-1][j-val[s1[d1]]]+1;
}
if(fx1[d1-1][j]!=-1)
{
if(fx1[d1][j]!=-1)
fx1[d1][j]=min(fx1[d1][j],fx1[d1-1][j]);
else
fx1[d1][j]=fx1[d1-1][j];
}
}
}
d2=0;
}
flag=false;
for(j=0;j<=v;j++)
{
if(fx2[d2][j]+fx1[d1][v-j]==lim&&fx2[d2][j]!=-1&&fx1[d1][v-j]!=-1)
flag=true;
}
}
}
printf("%d\n",ans);
return 0;
}
/*
6 15
6 1 13 5 4 1
*/