深度优先搜索(dfs)算法之四——性能优化
在竞赛中,我们有时会碰到一些题目,它们既不能通过建立数学模型解决,又没有现成算法可以套用,或者非遍历所有状况才可以得出正确结果。这时,我们就必须采用搜索算法来解决问题。
搜索算法按搜索的方式分有两类,一类是深度优先搜索,一类是广度优先搜索。
深度搜索编程简单,程序简洁易懂,空间需求也比较低,但是这种方法的时间复杂度往往是指数级的,倘若不加优化,其时间效率简直无法忍受;
所以,对程序进行优化,就成为搜索算法编程中最关键的一环。
4.1 细节优化
在深度优先搜索(dfs)算法之三——寻路中的N皇后问题中,每一层递归都需要进行判断上放、左斜线、右斜线是否有落子,常规思维是通过三个循环来判断,但是我们可以应用数学规律(同一直线上的点的行列和或差相等)简化,或者用二进制(位压)的特性来提高检测性能。
N皇后 应用数学规律优化
#include<bits/stdc++.h>
using namespace std;
int n,ans;
int x[100],y[100],k1[100],k2[100];
void out(){
if(ans<3){
for(int i=1;i<=n;i++)
cout<<x[i]<<' ';
cout<<'\n';
}
}
void dfs(int i){
if(i>n){
out();
ans++;
return;
}
for(int j=1;j<=n;j++){
if(y[j]==0&&k1[i-j+n]==0&&k2[i+j]==0){
y[j]=k1[i-j+n]=k2[i+j]=1;
x[i]=j;
dfs(i+1);
y[j]=k1[i-j+n]=k2[i+j]=0;
}
}
}
int main(){
cin>>n;
dfs(1);
cout<<ans;
return 0;
}
N皇后 二进制位压缩
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000
using namespace std;
int n,m,ans,a[maxn];
void dfs(int k,int l,int b,int r)
{
if(k>n)
{
if(++ans<=3)
{
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
return;
}
int s=~(l | b | r);
for(int i=1;i<=n;i++)
{
int bit = 1<<(i-1);
if(s & bit)
{
a[k]=i;
dfs(k+1,(l | bit)<<1,b|bit ,(r | bit)>>1);
}
}
}
int main()
{
scanf("%d",&n);
dfs(1,0,0,0);
printf("%d\n",ans);
return 0;
}
4.2 记忆化搜索
例题一、李白打酒加强版
话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒 斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店 次,遇到花 次。已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白这一路遇到店和花的顺序,有多少种不同的可能?
注意:壶里没酒( 斗)时遇店是合法的,加倍后还是没酒;但是没酒时遇花是不合法的。
输入数据格式
第一行包含两个整数 和 。