概述:
继续练习DFS的算法,便百度到了这一题,相比之前的两道题,这个题目却是可以称为一道难题了。
我一直觉得ACM中最难的就是把问题抽象为数学模型的步骤,以及联系过往知识算法的能力,这也是我最想要锻炼的东西。
本人不才,想了没多久发现不会做就去搜索别人的代码了。想要在初级阶段先通过别人的代码让自己熟悉起来,这样或许可以慢慢得心应手。
题目描述:
给定n个棒子,知道他们都是由x根长的棒子切割而来。求x的长度的最小值。(就是最大的x数目嘛)
算法思想:
最重要的思想仍然是DFS。
首先记录下每一根棒子的长度,用数组。然后记下来总长度是多少。因为最后的x长度一定能整除总长度。所以就枚举这些个长度。
这时候注意,是对于每一个固定的长度进行枚举。
在枚举的过程中,record数组的作用是记录当前的这根木棒是不是已经使用过了(1)还是没使用过(0),有这个数组的原因是因为要不断地调整子状态,去枚举来看是不是最后能够达到正好组合成功的状态。
这之后的dfs函数分为三个部分。
对于每一次长度的枚举,入口都是在cur_len = 0那个case下,在那个case下开启一轮dfs,然后结束之后把该点设回去,回到主函数,如果没有success就重新来一遍。
对于过程中,这里直接读代码吧我觉得可读性并不是很差。重要的是要理解整个的思想,是如何跳转状态,如果不会的话可以拿笔写下来。我个人也是琢磨了很长时间才能想明白这个方法。
最后就是cin和cout实在太慢啦,以后竞赛的时候我要避免这两者的使用。
代码部分:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
using namespace std;
int n,stick[67];
int len;
bool success,record[67];
bool cmp(int a, int b) {
return a > b;
}
void dfs(int dep, int cur_len, int u) {
if (success) return;
if (cur_len == 0) {
int k = 0;
while (record[k]) k++;
record[k] = 1;
dfs(dep + 1, stick[k], k + 1);
record[k] = 0;
return;
}
if (cur_len == len) {
if (dep == n) success = true;
else dfs(dep, 0, 0);
return;
}
for (int i = u; i < n; ++i) {
if (!record[i] && cur_len + stick[i] <= len) {
if (!record[i - 1] && stick[i] == stick[i - 1]) continue;
record[i] = 1;
dfs(dep+1, cur_len + stick[i], i + 1);
record[i] = 0;
}
}
}
int main() {
while (scanf("%d",&n) && n != 0) {
int sum = 0;
success = false;
for (int i = 0; i < n; ++i) {
scanf("%d",&stick[i]);
sum += stick[i];
}
sort(stick, stick + n, cmp);
for (len = stick[0]; len < sum; ++len) {
if (sum % len == 0) {
memset(record, 0, sizeof(record));
dfs(0, 0, 0);
if (success) break;
}
}
printf("%d\n", len);
}
return 0;
}

本文介绍了一种使用深度优先搜索(DFS)算法解决棒子切割问题的方法。通过枚举可能的切割长度并利用DFS进行状态转移,最终找到切割棒子的最大长度。文章详细解释了算法思想,并提供了完整的代码实现。

1559

被折叠的 条评论
为什么被折叠?



