剪枝

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 102 120 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!即可

posted @ 2019-11-07 17:47  tly2022  阅读(161)  评论(0编辑  收藏  举报