1432: 背包again
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 222 Solved: 65
SubmitStatusWeb Board
Description
Gy最近学习了01背包问题,无聊的他又想到了一个新的问题,给定n个物品的价值,和01背包一样,每个物品只能选1次或0次,求最小不能被得到的价值。
Input
第一行一个正整数T(T <= 100),表示有T组数据。
每组数据输入格式如下:
第一行为一个正整数N(N<=100),表示物品个数。
第二行N个正整数,表示每个物品的价值vi(1<=vi<=1000000)
Output
共输出T行,即每组数据相应答案。
Sample Input
Sample Output
可恶的数学题!
二进制表示,例:1=2^0,2=2^1,4=2^2,8=2^3
又二进制的1111=2^3+2^2+2^1+2^0=15;
不难看出,1111(即15以内所有的数)均可以用:2^0,2^1,2^2,2^3的二进制表示出来(1101,1001,1000,0101…………),那一位是1就加上这位代表的值(2^x)
所以证明了结论的正确性!
不难发现,类似于背包的二进制分解,1,2,4,8。......2^n,
对于这类连续的二的次方数,只要是下一个次方数以内的数,均可以用这几个书中的某几个表示出来;
例如 1,2,4,8 则16(不包含16) 以内的数均可以用这几个数表示;
所以打表出这些数,然后与比对,注意坑:要将数据先sort完之后再比对!!!!坑死我了
最后在筛查一下,对于大于maxn的数不必再考虑,找到小于maxn的数后,就让其加上这个值,因为maxn以内的值均可以表示了,
如果再出现一个小于maxn的数a,则maxn+a以内的数也就都可以表示了。
如果a大于maxn的话最小能表示的也是maxn+1还是没maxn小,所以不必考虑。
#include<bits/stdc++.h>
using namespace std;
int p[105]={1};
int main()
{
int t,i,j,n,k,a[105];
for(i=1;i<=27;++i) p[i]=p[i-1]*2;
cin>>t;
while(t--){int maxn=1;
cin>>n;
for(i=1;i<=n;++i) cin>>a[i];
sort(a+1,a+n+1);
for(i=1,j=0;i<=n;++i) if(a[i]==p[j]) {maxn=p[j+1];a[i]=0;++j;}
for(i=1;i<=n;++i){
if(a[i]&&a[i]<maxn) maxn+=a[i];
}
cout<<maxn<<endl;
}
return 0;
}