1. 程式人生 > >P1120 小木棍 [數據加強版]

P1120 小木棍 [數據加強版]

忘記 滿足 color c++ tin 剪枝 sam pre 搜索

題目描述

喬治有一些同樣長的小木棍,他把這些木棍隨意砍成幾段,直到每段的長都不超過50。

現在,他想把小木棍拼接成原來的樣子,但是卻忘記了自己開始時有多少根木棍和它們的長度。

給出每段小木棍的長度,編程幫他找出原始木棍的最小可能長度。

輸入輸出格式

輸入格式:

輸入文件共有二行。

第一行為一個單獨的整數N表示砍過以後的小木棍的總數,其中N≤65

(管理員註:要把超過50的長度自覺過濾掉,坑了很多人了!)

第二行為N個用空個隔開的正整數,表示N根小木棍的長度。

輸出格式:

輸出文件僅一行,表示要求的原始木棍的最小可能長度

輸入輸出樣例

輸入樣例#1: 復制
9
5 2 1 5 2 1 5 2 1
輸出樣例#1: 復制
6

說明

2017/08/05

數據時限修改:

-#17 #20 #22 #27 四組數據時限500ms

-#21 #24 #28 #29 #30五組數據時限1000ms

其他時限改為200ms(請放心食用)

搜索題,剪枝很重要

#include <bits/stdc++.h>
using namespace std;
#define maxn 100000
typedef long long ll;
#define inf 2147483647
#define ri register int

int n;
int a[maxn];
int
cnt = 0//真正的總個數 int tot = 0//真正的總和 bool used[maxn]; int x; bool cmp(int x, int y) { return x > y; } //G組數,sum當前已裝載大小,target每組目標大小,cur當前遍歷到的位置 void dfs(int G, int sum, int target, int cur) { if (G == 0) { cout << target; exit(0); } if (sum == target) { dfs(G - 1, 0, target, 1
); return; } if (sum + a[cnt] > target) //最小的都放不進直接pass return; for (int i = cur; i <= cnt; i++) { if (used[i]) continue; //平淡的回溯 used[i] = true; sum += a[i]; dfs(G, sum, target, i); sum -= a[i]; used[i] = false; if (sum == 0 || sum + a[i] == target) //如果像這樣已經滿足目標的都exit不了,那麽就沒必要繼續下去,因為接下來裝的數目的也是跟之前一樣的 break; while (a[i] == a[i + 1]) //這個數都過不了,相同的數也別想過 i++; } } int main() { ios::sync_with_stdio(false); // freopen("test.txt", "r", stdin); // freopen("outout.txt","w",stdout); cin >> n; for (int i = 1; i <= n; i++) { cin >> x; if (x <= 50) { a[++cnt] = x; tot += x; } } sort(a + 1, a + 1 + cnt, cmp); //從大到小排次序,能優化不少 for (int i = a[1]; i <= tot / 2; i++) { if (tot % i == 0) dfs(tot / i, 0, i, 1); } cout << tot; return 0; }

P1120 小木棍 [數據加強版]