思路:
回溯题基本写法。
- 用
multiset<int>
去记录数字的使用情况。 - 用
set<vector<int>>
去重。 - 剪枝:虽然数字可以重复使用(如果有的话),但是每一层的数字不应出现重复枚举。
比如:
2 2 2 2 2
每一层都应该放只能放2,而不是对2这个数字进行多次搜索。
class Solution {
public:
multiset<int> nums;
set<vector<int>> res;
int len ;
int numSquarefulPerms(vector<int>& A) {
len = A.size();
for(int x:A){
nums.insert(x);
}
vector<int> list;
dfs(0,list,A);
return res.size();
}
void dfs(int dpt,vector<int> &list,vector<int>& A){
if(dpt == len){
res.insert(list);
return;
}
unordered_set<int> optional;
for(int x:A){
if(nums.count(x)){
if( dpt<1 || check(x+list[dpt-1])){
optional.insert(x);
}
}
}
for(unordered_set<int>::iterator it=optional.begin();it!=optional.end();it++){
int x = *it;
list.push_back(x);
nums.erase(nums.find(x));
dfs(dpt+1,list,A);
list.pop_back();
nums.insert(x);
}
}
bool check(int x){
int r = int(sqrt(x)+0.5);
return x == r*r;
}
};