Sticks (經典搜尋加剪枝)
Sticks
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 30 Accepted Submission(s) : 7
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
George took sticks of the same length and cut them randomly until all parts became at most 50 units long. Now he wants to return sticks to the original state, but he forgot how many sticks he had originally and how long they were originally. Please help him and design a program which computes the smallest possible original length of those sticks. All lengths expressed in units are integers greater than zero.
Input
The input contains blocks of 2 lines. The first line contains the number of sticks parts after cutting, there are at most 64 sticks. The second line contains the lengths of those parts separated by the space. The last line of the file contains zero.
Output
The output file contains the smallest possible length of original sticks, one per line.
Sample Input
9 5 2 1 5 2 1 5 2 1 4 1 2 3 4 0
Sample Output
6 5
這道題問的是給你n個棍子,然後下面輸入n個數,讓你求他們最小組成棍子的長度是多少
是經典的搜尋+剪枝;
首先我需要把棍子的總長求出來然後有六步剪枝:
1.從大到小排序,因為最小的棍長一定是大於等於最大的單位棍子長度。
2.如果我當前模除長度不為0那麼這個一定也組不成棍長。
3.如果我找到了最小長度,那麼就不找了結束就行
4.如果我vis= 0說明我沒匹配到那麼也不用找了
5.防止重複的查詢
6.既然我已經找到了一組,因為有for我還要執行多餘步驟所以我截止就行
# if 01
# include <iostream>
# include <cstring>
# include <algorithm>
# include<functional>
using namespace std;
const int maxn = 70;
bool book[maxn];
int m[maxn], n;
bool flag;
void dfs(int z, int len, int c, int vis, int f)//z是當前合成棍子的個數,len是目標棍子的長度,c是統計當前合成了幾個棍子, vis是當前的長度, f是當前的下標
{
if(z == c)
{
flag = true;
return ;
}
for(int i = f; i < n; i++)
{
if(!book[i])
{
if(vis + m[i] == len)
{
book[i] = true;
dfs(z, len, c + 1, 0, 0);
if(flag)//第三步剪枝如果我找到了那麼我就不找了,也就不用回溯了
{
return ;
}
book[i] = false;
return ;//第六步它在迴圈裡面所以直接return防止費時間
}
else if(vis + m[i] < len)
{
book[i] = true;
dfs(z, len, c, vis + m[i], i + 1);
if(flag)//第三步剪枝如果我找到了那麼我就不找了,也就不用回溯了
{
return ;
}
book[i] = false;
if(vis == 0) //第四步剪枝如果我這根棍子還是0說明找不到匹配的
{
return ;
}
while(m[i] == m[i + 1])//第五步去重防止重複計算;
{
i++;
}
}
}
}
}
int main(int argc, char *argv[])
{
while(cin >> n, n)
{
int sum = 0;
for(int i = 0; i < n; i++)
{
cin >> m[i];
sum += m[i];
}
flag = false;
sort(m, m + n, greater<int>());//第一步剪枝,從大到小排序,最小的棍子也大於等於最大的單位長度
for(int i = m[0]; i <= sum; i++)
{
if(!(sum % i))//第二步剪枝如果我能整除開說明可以結合整棍子
{
memset(book, false, sizeof(book));
dfs(sum / i, i, 0,0,0);//
if(flag)
{
cout << i << endl;
break;
}
}
}
}
return 0;
}
# endif