这个题就是蓝书上边的小猫爬山和假日团队赛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;
}