給定 n 根木棍長度,能否拼成邊長相等的正多邊形(或多條等長木棍)。求最小可能邊長(即最小可行目標長度)。
總長度 sum。目標邊長 L 必須滿足:L ≥ max(棍長),L 整除 sum。枚舉 L 從 max 到 sum,檢查能否將所有木棍分組,每組和為 L。
while (a[i+1]==a[i]) i++;。if (cur_len == 0) break; 在嘗試失敗後退出循環。int n, stick[100], vis[100], target, sides;
bool dfs(int idx, int cur_len, int formed) {
if (formed == sides) return true; // 所有邊完成
if (cur_len == target) // 當前邊完成,開始下一邊
return dfs(0, 0, formed+1);
int prev = -1;
for (int i=idx; i target || stick[i] == prev) continue;
vis[i] = 1;
if (dfs(i+1, cur_len + stick[i], formed)) return true;
vis[i] = 0;
prev = stick[i];
if (cur_len == 0) break; // 首根棍失敗,無需嘗試其他
if (cur_len + stick[i] == target) break; // 湊滿失敗,無需嘗試其他
}
return false;
}
int main() {
while (scanf("%d", &n), n) {
int sum=0, mx=0;
for (int i=0; i());
for (target=mx; target<=sum; target++) {
if (sum % target) continue;
sides = sum / target;
memset(vis, 0, sizeof(vis));
if (dfs(0, 0, 0)) { printf("%d\n", target); break; }
}
}
}
文中提供大量測試用例及答案,可用於驗證剪枝正確性。
| 剪枝 | 代碼位置 | 效果 |
|---|---|---|
| 降序 | sort(greater) | 大棍優先,失敗快 |
| 同長跳過 | prev 變量 | 避免重複排列 |
| 首根固定 | cur_len==0 break | 消除對稱性 |
| 湊滿失敗斷 | cur_len+stick==target break | 最後一根失敗無替代 |
剪枝後實際搜索極小,n≤64 瞬時通過。屬於 NP 完全問題(多路數分割),剪枝是關鍵。
此題是「DFS + 剪枝」教科書級案例,四大剪枝技巧通用於子集和、分割、排列組合搜索問題。