OJ题目:click here~~
题目分析:总结一下就是,给n个数,这n个数中任意多个数的和的最大值,而且和不超过m。
由于n 在 [1 30]中,所以不可能直接表示出所有的状态。且m 在[1 10000000]中,也不能直接背包。可以将n个数分成两个部分。分别表示出两个部分的所有状态,与该状态下的和。最后再两个有序表中选择满足条件的值。
处理两个有序表时,用O(2*n)的方法,否则会超时。
AC_CODE
int n , m, len1 , len2;
int dp1[1<<16] , dp2[1<<16] , x1[16] , x2[16];
void consume(int dp[] , int x[] , int len)
{
int i , j , t;
for(i = 0;i < (1<<len);i++)
{
t = 0;
for(j = 0;j < len;j++)
{
if(i&(1<<j)) t += x[j];
}
dp[i] = t;
}
}
int GET()
{
int i , j , s , ans = 0;
j = (1<<len2) - 1;//!!!!!!!
for(i = 0;i < (1<<len1);i++)
{
for(; j >= 0;j--)
{
s = dp1[i] + dp2[j];
if(s <= m)
{
ans = MAX(ans , s);
if(ans == m) return ans;
break;
}
}
}
return ans;
}
int main(){
int i , t;
while(scanf("%d%d",&n,&m) != EOF)
{
len1 = (n>>1);
for(i = 0;i < len1;i++)
scanf("%d",&x1[i]);
consume(dp1 , x1 , len1);
len2 = n - len1;
for(i = 0;i < len2;i++)
scanf("%d",&x2[i]);
consume(dp2 , x2 , len2);
sort(dp1 , dp1 + (1<<len1));
sort(dp2 , dp2 + (1<<len2));
printf("%d\n",GET());
}
return 0 ;
}