本以为是一道水题,但死活只能拿到27分,总之详情见代码。
本题我用了4类剪枝,剪枝(1,2)没什么好说的,这里说一下剪枝(3,4):
剪枝(3):如果当前原始木棒中“尝试拼入的第一根木棒”的递归分支就返回失败,那么直接判定当前分支失败;
剪枝(4):如果在当前原始木棒中拼入一根木棒后,木棒恰好被拼接完整,并且“接下来拼接剩余木棒”的递归分支返回失败,那么直接判定当前分支失败。
以上两个剪枝分别利用了“空木棒的等效性”和“贪心”。
代码实现如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (register int i = (a); i <= (b); i++) const int maxn = 1e2; int n, cnt, len, tot; int a[maxn]; bool vis[maxn]; int cmp(int a, int b) {return a > b;} void origin() {memset(vis, 0, sizeof(vis));} int read() { int x = 0, flag = 0; char ch = ' '; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') { flag = 1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0'; ch = getchar(); } return flag ? -x : x; } int dfs(int stick, int cab, int last) { if (stick > cnt) return 1; if (cab == len) return dfs(stick + 1, 0, 1); int fail = 0;//剪枝(2),不解释. rep(i, last, n) { if (!vis[i] && cab + a[i] <= len && a[i] != fail) { vis[i] = 1; if (dfs(stick, cab + a[i], i + 1)) return 1; fail = a[i]; vis[i] = 0; if (!cab || cab + a[i] == len) return 0;//剪枝(3,4). } } return 0; } void write(int x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) write(x / 10); putchar(x % 10 + '0'); } int main() { int sum = 0, val = 0; n = read(); rep(i, 1, n) { int u = read(); if (u > 50) continue; else { a[++tot] = u; sum += u; val = max(u, val); } } sort(a + 1, a + n + 1, cmp);//剪枝(1),不解释. //一开始用的宏定义rep,WA的只有27分. for (len = val; len <= sum; len++) { if (sum % len) continue; cnt = sum / len; origin(); if (dfs(1, 0, 1)) { write(len); break; } } return 0; }