网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
一个正整数,即最少需要的组数。
数据范围
1≤n≤10
输入样例:
6
14 20 33 117 143 175
输出样例:
3
题目分析与算法设计:
给定n个数字分成互质组,那么考虑最坏的情况,要分成n组(n个数均不互质)。因为题目的数据量并不大,可以采用DFS解决,具体思路如下:
预备工作:准备一个数组存输入数据,准备一个容器,用于存不同的组,准备一个检索函数,可以检索指定分组内是否存在与目的数字重合的
- **开始DFS:**首先是递归终止条件,判断是否搜到末尾,搜到末尾则更新组数计数的值,返回;
- **继续:**每次在已有分组中从头开始搜索,用检索函数判断当前数字是否可以加入分组,若可以,加入后递归向下一个数字搜索
- **新建分组:**考虑组数为0的情况、找不到可以加入组的情况,应该设置创建新分组的情况,加入新分组后,同样递归向后搜索。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 11;
int n, p[N], cnt, ans = N;
vector<int> num[N]; //这里使用STL中的Vector,其长度可变,更方便模拟分组的状态
int gcd(int x, int y){
return y ? gcd(y, x % y) : x; //辗转相除求最大公约数
}
//判断两数是否互质
bool check(int x, int t){
for (int i = 0; i < num[t].size(); i++){
if (gcd(x, num[t][i]) > 1) return false;
}
return true;
void dfs(int now)
{
if (now == n){
ans = min(ans, cnt); //每次搜完取最小组数
return;
}
for (int i = 0; i < cnt; i++){
if (check(p[now], i)){
num[now].push_back(p[now]);
dfs(now + 1);
num[i].pop_back();
}
}
//需要考虑首次搜索无组可加、当前状态无组可加
num[cnt++].push_back(p[u]);
dfs(now + 1);
num[--cnt].pop_back();
}
int main(){
cin >> n;
for (int i = 0; i < n; i++) cin >> p[i];
dfs(0);
cout << ans << endl;
return 0;
}
三、剪枝优化、题型归纳总结(未完待续)
在通过搜索解决实际问题的过程中,我们是通过穷举每种情况来寻找合法解,然而在一些情况比较复杂的题目、数据量较强的题目中,由于算法的时间复杂度较高、数据规模过大,从而会导致运行超时甚至程序卡死,因此在对复杂问题的答案进行搜索时,我们应该灵活的针对每种题型设计对应的搜索规则并进行优化,通常通过设置剪枝、排除无效情况、对问题进行适当的转化等手法对搜索算法进行优化,使算法高效的执行并得出我们想要的结果。
对算法的剪枝与优化堪称是爆搜算法的精髓,如何合理的设置剪枝优化直接关系能否得到结果,这对我们的解题思维是一个很大的挑战,本板块将对常见的剪枝优化思路、对细节的处理进行归纳总结。
概述:剪枝与优化
①.剪枝与优化的原则
1.正确性
剪枝优化的过程是使算法逼近最优解的过程,而不是使算法远离最优解甚至跳过最优解的过程。剪枝的前提是保证对最优解不丢不漏。
2.准确性
在保证正确性的前提下,我们采取必要的手段使算法跳过一定不含有目标状态/最优解的分支,从而保证算法高效地进行并更迅速的找出
3.高效性
设计优化程序的根本目的,是要减少搜索的次数,使程序运行的时间减少. 但为了使搜索次数尽可能的减少,我们又必须花工夫设计出一个准确性较