送礼物
达达帮翰翰给女生送礼物,翰翰一共准备了N个礼物,其中第i个礼物的重量是G[i]。
达达的力气很大,他一次可以搬动重量之和不超过W的任意多个物品。
达达希望一次搬掉尽量重的一些物品,请你告诉达达在他的力气范围内一次性能搬动的最大重量是多少。
输入格式 第一行两个整数,分别代表W和N。
以后N行,每行一个正整数表示G[i]。
输出格式 仅一个整数,表示达达在他的力气范围内一次性能搬动的最大重量。
数据范围 1≤N≤46, 1≤W,G[i]≤231−1 输入样例: 20 5 7 5 4 18 1 输出样例: 19
首先本题使用dfs算法寻找数据的所有组合,挑选其中合法的最大的值。
如果是简单的暴搜的话,2^46的搜索量的话一定会超时的,我们这里利用一个技巧:
先对前半部分进行搜索将得到存储到数组中;
然后在对后半部分进行搜索,在搜索结束时,在利用二分的方法在前半部分中寻找合法且最大的值。这样O(2^23)+O( 2 ^23)*O(log(n/2))的数据量会明显降低数据搜索量
#include <iostream>
#include <algorithm>
using namespace std
;
const int N
=1<<24;
typedef long long LL
;
int weights
[N
],g
[50];
int n
,m
,k
;
int cnt
=0;
int ans
=0;
void dfs(int u
,int s
)
{
if(u
==k
)
{
weights
[cnt
++]=s
;
return;
}
if((LL
)s
+g
[u
]<=m
)
dfs(u
+1,s
+g
[u
]);
dfs(u
+1,s
);
}
void dfs2(int u
,int s
)
{
if(u
==n
)
{
int l
=0,r
=cnt
-1;
while(l
<r
)
{
int mid
=l
+r
+1>>1;
if((LL
)s
+weights
[mid
]<=m
)l
=mid
;
else r
=mid
-1;
}
if((LL
)s
+weights
[l
]<=m
)ans
=max(ans
,s
+weights
[l
]);
return;
}
if((LL
)s
+g
[u
]<=m
)dfs2(u
+1,s
+g
[u
]);
dfs2(u
+1,s
);
}
int main()
{
cin
>>m
>>n
;
for(int i
=0;i
<n
;i
++)
cin
>>g
[i
];
sort(g
,g
+n
);
reverse(g
,g
+n
);
k
=n
/2+2;
dfs(0,0);
sort(weights
,weights
+cnt
);
int t
=1;
for(int i
=0;i
<cnt
;i
++)
if(weights
[i
]!=weights
[i
-1])
weights
[t
++]=weights
[i
];
dfs2(k
,0);
cout
<<ans
<<endl
;
return 0;
}