**经常考?
剪枝
1.从大到小枚举:分支数会少一些,越往下都剪枝越少,也越快
2.如果搜的时候,当前搜的这个数和前一个数相等并且失败了,当前也一定失败。
也就是说如果ai无解,那么后面和他相等的数应该也是无解的;
所以可以跳过。
3.如果某一组第一个数失败了,那么后面的数一定无解;
4.如果某一组最后一个数失败了,那么后面的数一定无解;
当前组的最后一个元素ai (注意此时当前子数组的其他元素与ai的和一定是sum / k) 的搜索结果是失败(即当前组后面的所有组全部搜索完后是失败), 那么最终的结果是失败.
**
class Solution {
public:
int len;
vector<int>nums;
vector<bool>st;
bool dfs(int start,int cur,int k)
{
if(k==0) return true;
if(cur==len) return dfs(0,0,k-1);
for(int i=start;i<nums.size();i++) //起点要从start开始
{
if(st[i]) continue;
if(cur+nums[i]<=len)
{
st[i]=true;
if(dfs(i+1,cur+nums[i],k)) return true;
st[i]=false;
}
while(i+1<nums.size() && nums[i]==nums[i+1]) i++; //如果当前元素和后面元素重复,跳过,前面不行后面也不行
if(!cur || cur+nums[i]==len) return false;//如果是当前组的第一个元素不行或者加上最后一个元素正好等于分组的大小的话,那么也是错误的
}
return false;
}
bool canPartitionKSubsets(vector<int>& _nums, int k) {
nums=_nums;
st.resize(nums.size());
int sum=accumulate(nums.begin(),nums.end(),0);
if(sum%k) return false;
len=sum/k;
sort(nums.begin(),nums.end(),greater<int>()); //从大到小排序,注意!
return dfs(0,0,k);
}
};