题目传送:Sticks
思路:DFS + 剪枝
AC代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <vector> #include <map> #include <set> #include <deque> #include <cctype> #define LL long long #define INF 0x7fffffff using namespace std; int s[65]; int vis[65]; int n; int sum; int len; int flag; bool cmp(int a, int b) { return a > b; } void dfs(int cnt, int l, int pos) {//cnt表示现在选了的木条数,l表示正在选的木条的总长度,pos表示下一个开始选的木条的下标 if(flag) return; if(l == 0) {//当前状态还没选木条 for(int i = 0; i < n; i ++) { if(!vis[i]) { vis[i] = 1; dfs(cnt + 1, s[i], i + 1); vis[i] = 0; break; } } } else if(l == len) {//当前状态的长度满足初始长度,则找到一组符合的 if(cnt == n) flag = 1;//全部都找到了 else dfs(cnt, 0, 0);//继续找 } else {//当前状态木条总长度没选够,继续选 for(int i = pos; i < n; i ++) { if(!vis[i] && l + s[i] <= len) { if(!vis[i - 1] && s[i] == s[i-1]) continue;//去重剪枝,不剪枝对于最坏情况会超时 vis[i] = 1; dfs(cnt + 1, l + s[i], i + 1); vis[i] = 0; } } } } int main() { while(scanf("%d", &n) != EOF) { if(n == 0) break; sum = 0; for(int i = 0; i < n; i ++) { scanf("%d", &s[i]); sum += s[i]; } sort(s, s + n, cmp);//从大到小排序,必须要先选大的,再选小的,否则会出错 flag = 0; for(len = s[0]; len <= sum; len ++) {//依次枚举长度 if(sum % len == 0) {//当长度满足整除sum才可以进行dfs memset(vis, 0, sizeof(vis)); dfs(0, 0, 0); if(flag) { cout << len << endl;//找到则输出,跳出循环 break; } } } } return 0; }
时间: 2024-12-15 01:38:26