poj 1011 回溯+剪枝 木棒问题
2013-05-10 11:51
323 查看
【题意】:乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
1.把所有木棍的长度从大到小排列,组合木棒时优先使用长的木棍,这样可以加快组合速度,并且对后面的剪枝有帮助。
2.木棒的长度一定是大于等于最长木棍的长度并且小于等于所有木棍长度的和,这个很容易证明。
3.木棒的长度一定是所有木棍长度的和的约数,这个也很容易证明。
4.在某一个木棒的组合过程中,对于当前的木棍stick[i],如果stick[i-1]没有被组合并且stick[i] == stick[i-1],那么不用考虑stick[i],显然stick[i]最终也不会被组合。
5.如果此次是在尝试第i个木棒的第一段,假设stick[j]为当前可以被使用的最长的木棍,如果此次组合失败,直接退出搜索,即退回到对第i-1个木棒的搜索。试想:失败说明现在使用stick[j]是不可行的,那么以后无论什么时候使用stick[j]都是不可行的,因为以后再处理stick[j]时可使用的木棍一定是当前可使用的木棍的子集,在更多木棍选择的情况下都不能组合成功,那么,在更少木棍选择的情况下一定不能组合成功。
#include <iostream>
#include <algorithm>
using namespace std;
int sticks[64], n, len, num;
bool used[64];
bool compare(int a, int b)
{
return a > b;
}
bool dfs(int cur, int left, int level)
{ //cur: 当前已经计算的木棒编号,left:该段还剩的长度,level:已经成功的木棒数
if(left == 0) {//匹配一根木棒成功
if(level == num-2)
return true;
for(cur = 0; used[cur]; cur++)
;
used[cur] = true;
if(dfs(cur+1, len-sticks[cur], level+1))
return true;
used[cur] = false;
return false;
} else {
if(cur >= n-1)
return false;
for(int i = cur; i < n; i++) {
if(used[i])
continue;
if((sticks[i] == sticks[i-1]) && !used[i-1])
continue;
if(sticks[i] > left)
continue;
used[i] = true;
if(dfs(i, left-sticks[i], level))
return true;
used[i] = false;
}
return false;
}
}
int main()
{
while(cin>>n) {
if(n == 0)
break;
int sum = 0;
for(int i = 0; i < n; i++) {
scanf("%d", &sticks[i]);
sum += sticks[i];
}
sort(sticks, sticks+n, compare); //由大到小排序
bool end = false;
for(len = sticks[0]; len <= sum/2; len++) {
if(sum%len == 0) {
used[0] = true;
num = sum/len;
if(dfs(0, len-sticks[0], 0)) {
end = true;
printf("%d\n", len);
break;
}
used[0] = false;
}
}
if(!end)
printf("%d\n", sum);
memset(used, 0, sizeof(used));
}
//system("pause");
return 0;
}
http://ren.iteye.com/blog/344095 http://www.cppblog.com/y346491470/articles/155318.html http://blog.csdn.net/lyy289065406/article/details/6647960
1.把所有木棍的长度从大到小排列,组合木棒时优先使用长的木棍,这样可以加快组合速度,并且对后面的剪枝有帮助。
2.木棒的长度一定是大于等于最长木棍的长度并且小于等于所有木棍长度的和,这个很容易证明。
3.木棒的长度一定是所有木棍长度的和的约数,这个也很容易证明。
4.在某一个木棒的组合过程中,对于当前的木棍stick[i],如果stick[i-1]没有被组合并且stick[i] == stick[i-1],那么不用考虑stick[i],显然stick[i]最终也不会被组合。
5.如果此次是在尝试第i个木棒的第一段,假设stick[j]为当前可以被使用的最长的木棍,如果此次组合失败,直接退出搜索,即退回到对第i-1个木棒的搜索。试想:失败说明现在使用stick[j]是不可行的,那么以后无论什么时候使用stick[j]都是不可行的,因为以后再处理stick[j]时可使用的木棍一定是当前可使用的木棍的子集,在更多木棍选择的情况下都不能组合成功,那么,在更少木棍选择的情况下一定不能组合成功。
#include <iostream>
#include <algorithm>
using namespace std;
int sticks[64], n, len, num;
bool used[64];
bool compare(int a, int b)
{
return a > b;
}
bool dfs(int cur, int left, int level)
{ //cur: 当前已经计算的木棒编号,left:该段还剩的长度,level:已经成功的木棒数
if(left == 0) {//匹配一根木棒成功
if(level == num-2)
return true;
for(cur = 0; used[cur]; cur++)
;
used[cur] = true;
if(dfs(cur+1, len-sticks[cur], level+1))
return true;
used[cur] = false;
return false;
} else {
if(cur >= n-1)
return false;
for(int i = cur; i < n; i++) {
if(used[i])
continue;
if((sticks[i] == sticks[i-1]) && !used[i-1])
continue;
if(sticks[i] > left)
continue;
used[i] = true;
if(dfs(i, left-sticks[i], level))
return true;
used[i] = false;
}
return false;
}
}
int main()
{
while(cin>>n) {
if(n == 0)
break;
int sum = 0;
for(int i = 0; i < n; i++) {
scanf("%d", &sticks[i]);
sum += sticks[i];
}
sort(sticks, sticks+n, compare); //由大到小排序
bool end = false;
for(len = sticks[0]; len <= sum/2; len++) {
if(sum%len == 0) {
used[0] = true;
num = sum/len;
if(dfs(0, len-sticks[0], 0)) {
end = true;
printf("%d\n", len);
break;
}
used[0] = false;
}
}
if(!end)
printf("%d\n", sum);
memset(used, 0, sizeof(used));
}
//system("pause");
return 0;
}
http://ren.iteye.com/blog/344095 http://www.cppblog.com/y346491470/articles/155318.html http://blog.csdn.net/lyy289065406/article/details/6647960
相关文章推荐
- poj1011 木棒问题
- poj 1011 sticks(木棒) (dfs+剪枝)
- poj 1011 sticks 经典剪枝问题
- POJ_1321——棋盘问题,回溯+剪枝
- poj 1011 Sticks(经典搜索问题:DFS+剪枝)
- POJ 1011 Sticks(DFS回溯剪枝)
- POJ 1011 最小的木棒 (dfs+剪枝|| 搜索好题)
- 搜索剪枝回溯经典题目 pku 1011 sticks
- POJ1011 木棒
- POJ 1011 Sticks 【深搜+剪枝】
- POJ 1011:木棒
- poj 2363 poj 1011 dfs + 剪枝
- poj1011-Sticks dfs各种剪枝
- poj 1011 DFS+剪枝
- POJ 1321 棋盘问题(DFS+回溯)
- poj 2533 N皇后问题 -- 递归回溯(打表)
- poj_1011木棒
- poj1321 棋盘问题 回溯
- POJ 2531 dfs回溯(小剪枝)
- POJ---- Pots ----BFS的路径回溯问题