深度优先搜索就是按照深度优先的顺序对“问题状态空间“进行搜索的算法。我们可以把”问题空间“类比为一张图,其中的状态类比为节点,状态之间的联系与可达性就用图中的边来表示,那么深度优先搜索算法求解问题,就相当于在一张图上进行深度优先遍历。
深度优先搜索与”递归“和”栈“密切相关。我们认为”递归“是与递推相对的一种单纯的遍历方法,除了搜索之外,还有很多算法都可以用递归实现。而”深搜“是一种单纯的遍历形式、状态记录与检索、剪枝优化等算法整体设计的统称。
在研究深度优先搜索算法之前,我们先来定义该过程产生的”搜索树“结构。在对树进行深度优先遍历处于点x时对于某些边(x,y),y是一个尚未访问过的节点,程序从x成功进入了更深层对y的递归;对于另外一些边(x,y),y已经被访问过,从而程序继续考虑其他分支。我们称所有点(问题空间的状态)与成功发生递归的边(访问两个状态之间的移动)构成的树是一棵“搜索树”。整个深搜的过程是基于该搜索树完成的——为了避免重复访问,我们对状态进行记录和检索;为了使程序更加高效,我们提前减除搜索树上不可能的答案的子树和分支,不去进行遍历。
我们发现这道题目有两个可以剪枝的部分,一个是如果当前的答案已经大于了我们已知的最小答案,不用说直接return返回即可.第二个剪枝则是,我们可以将小猫的体重从大到小排序,这样我们的搜索树就会缩短许多,至于为什么,因为我们的剩余空间就变小了,然后可选择的猫也就少了。
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX_N 18
int cat[MAX_N+5],cab[MAX_N+5];
int n,w,ans=100;
bool cmp(int a,int b)
{
return a>b;
}
void dfs(int now,int cnt)
{
if(cnt>=ans)return ;
if(now>n)
{
ans=min(ans,cnt);
return ;
}
for(int i=1;i<=cnt;i++)
{
cab[i]+=cat[now];
if(cab[i]<=w)dfs(now+1,cnt);
cab[i]-=cat[now];
}
cab[cnt+1]=cat[now];
dfs(now+1,cnt+1);
cab[cnt+1]-=cat[now];
return ;
}
int main()
{
cin>>n>>w;
for(int i=1;i<=n;i++)cin>>cat[i];
sort(cat+1,cat+1+n,cmp);
dfs(1,0);
cout<<ans;
return 0;
}
1.在每个状态下,从所有未填的位置里选择”能填的合法数字“最少的位置,考虑该位置填什么数,而不是任意找出一个位置。
2.使用位运算代替数组执行”对熟读各个位置所填数字的记录“以及”可行性的检查与统计“,这就是常说的”常数优化“。
(1).对于每行、每列、每个九宫格,分别用一个9位二进制数保存哪些数字可以填。
(2).对于每个位置,把他在行、列、九宫格的3个二进制数做位与运算,可以得到该位置能填哪些数。
(3).在一个位置填上某个数后,把该位置所在的行、列、九宫格记录的二进制数对应的位改为0,即可更新当前状态,回溯时改成1,即可还原现场。
#include<iostream>
using namespace std;
#define MAX_N 9
#define MAX_M 1<<MAX_N
char str[100];
int ones[MAX_M],map[MAX_M];
int row[MAX_N],col[MAX_N],cell[3][3];
int flag=0;
void Init()
{
for(int i=0;i<MAX_N;i++)row[i]=col[i]=(1<<MAX_N)-1;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
cell[i][j]=(1<<MAX_N)-1;
}
void draw(int x,int y,int t,bool flag)
{
if(!flag)str[x*MAX_N+y]='.';
else str[x*MAX_N+y]='1'+t;
int v=1<<t;
if(!flag)v=-v;
row[x]-=v;
col[y]-=v;
cell[x/3][y/3]-=v;
}
int lowbit(int x)
{
return x&-x;
}
int get(int x,int y)
{
return row[x]&col[y]&cell[x/3][y/3];
}
void dfs(int cnt)
{
if(!cnt)
{
flag=1;
return ;
}
int min_v=10;
int x,y;
for(int i=0;i<MAX_N;i++)
for(int j=0;j<MAX_N;j++)
if(str[i*MAX_N+j]=='.')
{
int state=get(i,j);
if(min_v>ones[state])
{
x=i,y=j;
min_v=ones[state];
}
}
int state=get(x,y);
while(state)
{
int t=map[lowbit(state)];
state-=lowbit(state);
draw(x,y,t,true);
dfs(cnt-1);
if(flag)return ;
draw(x,y,t,false);
}
return ;
}
int main()
{
for(int i=0;i<MAX_N;i++)map[1<<i]=i;
for(int i=0;i<MAX_M;i++)
for(int j=0;j<MAX_N;j++)
ones[i]+=i>>j&1;
while(cin>>str,str[0]!='e')
{
Init();
int cnt=0;
flag=0;
for(int i=0;i<MAX_N;i++)
for(int j=0;j<MAX_N;j++)
if(str[i*MAX_N+j]!='.')
{
int t=str[i*MAX_N+j]-'1';
draw(i,j,t,true);
}
else cnt+=1;
dfs(cnt);
puts(str);
}
return 0;
}