剪枝
DFS(深度优先搜索)是一种常见的算法,大部分的题目都可以用 DFS 解决,
但是大部分情况下,这都是骗分算法,很少会有爆搜为正解的题目。
因为 DFS 的时间复杂度特别高。(没学过 DFS 的请自行补上这一课)
既然不能成为正解,那就多骗一点分吧。
那么这一篇文章将介绍一些实用的优化算法(俗称“剪枝”)。
题目:求9个数字以内的全排列 (我们以三个数字的为例子)
正常猛男大力搜索代码(
#include<bits/stdc++.h>
using namespace std;
int a[3];
int dfs(int n){
if(n==3){
for(int i=0;i<3;i++)
printf("%d",a[i]);
return 0*printf("\n"); //看不懂的考虑下函数返回值的问题
}
for(int i=0;i<3;i++){
a[n]=i; dfs(n+1); //不能用n++或者++n;
}
}
int main(){
int t=dfs(0);
}
得到的结果 000 001 002 010 011 012 020 021 022 100 101 102。。。
我们想要的结果 012 021 102120 201 210
如何只把我们需要的答案输出出来?
我们经常用的剪枝有:可行性剪枝、最优性剪枝、记忆化搜索、搜索顺序剪枝。
其中可行性剪枝就是把能够想到的不可能出现的情况给它剪掉 。
该方法判断继续搜索能否得出答案,如果不能直接回溯。
比如a[0]=0时,a[1]便不能为0了
#include<bits/stdc++.h>
using namespace std;
int a[3],b[3];
int dfs(int n){
if(n==3){ for(int i=0;i<3;i++)
printf("%d",a[i]);
return 0*printf("\n"); //看不懂的考虑下函数返回值的问题
} for(int i=0;i<3;i++){
if(b[i]){ b[i]=0; a[n]=i; dfs(n+1); //不能用n++或者++n;
b[i]=1;
}
}
}
int main(){
for(int i=0;i<3;i++)
b[i]=1;
int t=dfs(0);
}
如果我们想打表:
#include<bits/stdc++.h>
using namespace std;
int qqq=4,num=0;
int a[10],b[10];
int dfs(int n){
if(n==qqq){
num++;
return 0;
}
for(int i=0;i<qqq;i++){
if(b[i]){
b[i]=0;
a[n]=i;
dfs(n+1); b[i]=1;
}
}
}
int main(){
for(qqq=1;qqq<5;qqq++){
num=0;
for(int i=0;i<qqq;i++)
b[i]=1;
int t=dfs(0);
printf("%d\n",num);
}
}
得到:1 2 6 24
进入http://oeis.org
我们发现还有很多公式,
那我们把1-9都打出来 1 2 6 24 120 720 5040 40320 362880
进入http://oeis.org,我们发现少了一些。
由此,我们发现 A000142就是我们要的
即n个数字全排列,总方案数为N!
如果题目要我们求n个数字全排列的总方案数,我们不必再搜索一遍,直接输出N!即可