题目大意:
给不超过20根棍子,问是否能分成长度相等的四组
分析:
先判断能不能分,总和能被4整除且除以4大于最长的棍子。
然后就排个序DFS,每拼好一组重设参数继续搜下一组,搜到三组就不用再找了,剩下的一定能拼成第四组。
注意两个地方需要剪枝,不然会TLE:
1.如果当前这一根搜索失败,后面所有和它长度相等的都可以跳过
2.在搜某一组时,从上一根棒子的位置开始找,因为前面要么是用过的、要么是搜索失败的,没必要重复搜
代码:
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
int n, num[20] = {0};
bool found, vis[20] = {0};
void dfs(int len, int now, int c, int start){
if (now == 0){//找到一组,重设参数
now = len;
c--;
start = 0;
}
if (c == 1) found = 1;//找到三组,跳出
if (found) return;
for (int i = start, last = -1; i < n; i++){//从上一根棒子的位置开始找
if (vis[i] || num[i] > now || num[i] == last) continue;
vis[i] = 1;
dfs(len, now-num[i], c, i+1);
if (found) return;
vis[i] = 0;
last = num[i];
}
}
bool cmp(int a, int b){
return (a > b);
}
int main(){
int t, sum, max;
cin >> t;
while (t--){
cin >> n;
sum = 0;
max = 0;
for (int i = 0; i < n; i++){
cin >> num[i];
sum += num[i];
if (num[i] > max) max = num[i];
}
if (sum/4*4 != sum || sum/4 < max) cout << "no" << endl;
else{
found = 0;
memset(vis, 0, sizeof(vis));
sort(num, num+n, cmp);
dfs(sum/4, sum/4, 4, 0);
if (found) cout << "yes" << endl;
else cout << "no" << endl;
}
}
return 0;
}