试题 算法训练 Sticks
资源限制
时间限制:1.0s 内存限制:999.4MB
Sticks
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 113547 | Accepted: 26078 |
问题描述
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.
输入格式
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.
输出格式
The output should contains the smallest possible length of original sticks, one per line.
样例输入
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
样例输出
6
5
题目大意:这个人把一堆等长的木棍切割成n块小木棍,后来他想把他们拼成同样长度的木棍,但是他不知道原始的木棍长度是多少,也不知道原始木棍的数目,所以现在就问要把这一堆木棍拼成同等长度的大木棍,需要拼成木棍的最短的长度。
思路:用dfs把满足的长度搜一遍,注意剪枝
剪枝:
1. 木棍符合结果的长度一定是总木棍长度的因数
2. 将木棍从大到小排序,则可以在比较少的次数里合成想要的那种长度
3. 在搜索过程中,如果前一个木棍没有成功拼接,那么后面与其相同的木棍也要被剪掉
4. 当一个木棍拼凑失败时,直接回溯,不再按照这个条件浪费时间
代码:
#include <bits/stdc++.h>
#define Max 101
using namespace std;
int sticks[Max],vis[Max];
int min_len; // 满足条件的最小长度
int stick_num;// 木棍数量
int n;// stick的数量
int total_len; // 木棍总长度
int cmp ( int a, int b){
return a > b;
}
/*
sum 指当前拼凑的这根木棍的长度
cur 指当前正在搜索的木棍下标
res 表示已经拼成的木棍的数量
k 表示假设的单个木棍的长度 -> min_len
*/
bool dfs(int sum, int cur, int res, int k){
if(res == stick_num){
return true;
}
for(int i = cur; i < n; i++){
//第i个被用了,或者与前一个木棍长度相同但是 前一个也没被用
//那么 这个也不能被用
if(vis[i] || (i && sticks[i] == sticks[i-1] && !vis[i-1])){
continue;
}
if(sticks[i] + sum == k) {
vis[i] = 1;
if(dfs(0, 0, res+1, k)){
return true;
}
vis[i] = 0; //虽然这步拼成了长度为x的木棍,但是剩下的不能成功拼凑,所以失败回溯
return false;
}
if(sticks[i] + sum < k) { //没拼好
vis[i] = 1;
if(dfs(sticks[i] + sum, i + 1, res, k)){
return true;
}
vis[i] = 0;
if(!sum) return false;
}
}
return false;
}
int main(){
while(cin >> n && n) {
total_len = 0;
for(int i = 0; i < n; i++) {
cin >> sticks[i];
total_len += sticks[i];
}
//从大到小排序 可以在比较少的次数里合成想要的那种长度
sort(sticks, sticks + n, cmp);
int flag = 0;
for(min_len = sticks[0]; min_len < total_len; min_len++){
//因为初始的木棍是等长的
if(total_len % min_len == 0) {
memset(vis, 0, sizeof(vis));
stick_num = total_len / min_len; // 可能的最多木棍数量
if(dfs(0,0,0,min_len)){
cout << min_len << endl;
flag = 1;
break;
}
}
}
if(!flag) {
cout << total_len << endl;
}
}
return 0;
}