1.题解 回溯 直接100%
class Solution {
public:
bool canPartitionKSubsets(vector<int>& nums, int k) {
int ans = accumulate(nums.begin(),nums.end(),0);
if(ans%k !=0)return false; //排除不可能的结果
int target = ans/k;
sort(nums.begin(),nums.end(),greater<int>()); //从大到小的排序,减少循环
if(*max_element(nums.begin(),nums.end())>target) return false;//如果有大于target的,肯定会报错。
vector<bool> used(nums.size(),false);
vector<int> bucket(k,0);
return dfs(bucket,used,0,0,target,nums);
}
bool dfs(vector<int> &bucket,vector<bool> &used,int b,int start,int target,vector<int>& nums) { //start为当前数字位置,b为当前的桶
if(b == bucket.size()) return true;
if(bucket[b] == target) return dfs(bucket,used,b+1,0,target,nums);
for(int i=start;i<nums.size();i++) {
if(bucket[b] + nums[i] > target) continue;
if(used[i]) continue;
used[i] = true;
bucket[b] += nums[i];
if(dfs(bucket,used,b,i+1,target,nums)) return true;
used[i] = false;
bucket[b] -= nums[i];
if(bucket[b] == 0) return false; //如果处理之后又bucket还为0,直接剪枝
}
return false;
}
};
2.题解 dp
class Solution {
int dp[(1 << 16) + 2];
public:
bool canPartitionKSubsets(vector<int>& nums, int k) {
int n = nums.size();
fill(dp,dp+(1<<16)+2,-1);
int sum = 0;
for(int i = 0;i < n;i++){
sum += nums[i];
}
if (sum % k != 0) return false;
int target = sum / k;
dp[0] = 0;
for(int mask = 0; mask < (1 << n);mask++){
if(dp[mask] == -1) continue;
for(int i = 0;i < n;i++){
if(!(mask & (1 << i)) && dp[mask] + nums[i] <= target)
dp[mask | (1 << i)] = (dp[mask] + nums[i]) % target; //能否刚好为0
}
}
return dp[(1 << n)-1] == 0; // 所有书取到
}
};