这个题就是蓝书上边的小猫爬山和假日团队赛48的A题的升级版啊...搜索+剪枝的思想
首先判断是否有一个物品的重量超过了箱子的承重,有的话就输出No,否则继续往下。
将这个题变为最少需要的箱子个数是否小于等于m个。dfs(x,sum)为第x个货物分配过程(前x-1个货物已经分配好了,用了sum个箱子),用cnt数组记录每个箱子装了多少吨,ans记录最少需要多少个箱子。
对于第x个货物有两种情况:
- 如果货物可以放在第 i 个箱子中,那么就将 cnt[i] 加上这个货物的重量并继续递归dfs(x+1,sum)
- 用一个新的箱子装这个货物,也就是令 cnt[sum+1] = wi 。然后继续递归 dfs(x+1,sum+1)
当x==n+1的时候说明到达了边界,更新答案ans并 return。为了防止超时,可以做一些操作,可以将货物按照重量由大到小排序,优先搜索重量大的货物,减少搜索次数;可以在搜索时判断当前的sum是否大于等于ans,如果是,说明答案不会更优直接return。
最后判断一下ans和m的大小,如果ans<=m输出Yes,否则输出No。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[20];
ll cnt[20];
ll ans;
ll n,m;
void dfs(ll x,ll sum)
{
if(sum>=ans) return;
if(x==n){
ans=min(ans,sum);
return;
}
for(ll i=0;i<sum;i++){
if(cnt[i]+a[x]<=m){
cnt[i]+=a[x];
dfs(x+1,sum);
cnt[i]-=a[x];
}
}
cnt[sum]=a[x];
dfs(x+1,sum+1);
cnt[sum]=0;
}
ll cmp(ll x,ll y)
{
return x>y;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll t;
cin>>t;
while(t--){
ll x;
cin>>n>>x>>m;
ll flag=1;
for(ll i=0;i<n;i++) {
cin>>a[i];
if(a[i]>m) flag=0;
}
if(!flag){
cout<<"No"<<endl;
continue;
}
sort(a, a+n , cmp);
ans=n;
dfs(0,1);
if(ans>x) flag=0;
if(!flag){
cout<<"No"<<endl;
continue;
}
cout<<"Yes"<<endl;
}
return 0;
}

京公网安备 11010502036488号