蓝桥杯——粘木棍 (C++)
题目来源:蓝桥杯算法训练
知识点:DFS搜索
问题描述
有N根木棍,需要将其粘贴成M个长木棍,使得最长的和最短的的差距最小。
输入格式
第一行两个整数N,M。
一行N个整数,表示木棍的长度。
输出格式
一行一个整数,表示最小的差距
样例输入
3 2
10 20 40
样例输出
10
数据规模和约定
N, M<=7
题目分析
暴力法 思路:列举所有可能的组合,比较求最小差距。显然这种做法在计算过程中包含大量的重复计算,耗时较长。
采用 DFS+穷举 的思路:每次选择两根木棍进行合并,新木棍加入数组,两个旧的舍去。n
根木棍要合并成m
根,相当于需要合并n - m
次,即舍去n - m
根旧的。
如何舍去旧木棍,加入新木棍呢?可以使用两层for
循环遍历,取出两根木棍,将合并的新长度放入其中一个旧木棍在数组中的位置,将另一个旧木棍的位置与最后n-1
的位置交换。在使用 DFS 进行搜索时,参数为当前数组长度,往下搜索时长度递减即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define MAX 9999
#define MIN -9999
const int maxn = 10;
int lens[maxn];
int n, m, d;
void DFS(int k) {
if(k == m) {
int maxL = MIN;
int minL = MAX;
for(int i=0; i<k; i++) {
if(lens[i] < minL) minL = lens[i];
if(lens[i] > maxL) maxL = lens[i];
}
d = min(d, maxL - minL);
return;
}
for(int i=0; i<k; i++) {
for(int j=i+1; j<k; j++) {
lens[i] += lens[j];
swap(lens[j], lens[k-1]);
DFS(k-1);
swap(lens[j], lens[k-1]);
lens[i] -= lens[j];
}
}
}
int main() {
cin >> n >> m;
for(int i=0; i<n; i++) {
cin >> lens[i];
}
d = MAX;
DFS(n);
cout << d << endl;
return 0;
}
注意:
- 进行DFS 时,当数组长度
k
等于m
,说明已经完成分组。此时找出数组中的最大值与最小值,但不能对数组进行排序,因为会打乱数组顺序。 - 完成 DFS 回到上一步时,要恢复合并之前的两根木棍的长度和位置。