题目大意:
给不超过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; }