当普通dfs搜索答案时,有时会有搜索的深度较深状态较多,而答案所在的深度却比较小的情况。比如说下面这个图中,目标状态是红框的那个点,它的深度很小,但是左侧有很多的状态,普通dfs必须要搜完左侧所有状态才会搜到目标状态,这样就很容易超时。对此可以在dfs的时候限定一个深度的状态,这个深度是从小到大枚举的,直到搜到答案。
如果我们限定dfs的深度是1,那么就只有两个状态,目标状态第二次就搜到了,实现了dfs的优化。
但是个人认为这个算法还是只能对一些特定的题目有效,即目标状态的深度要小一点,否则优化的效率不大,极端情况下,目标状态的最深最右边的,反而用的时间会更长。
入门例题:hdu2234
题意:给出一个4*4的矩阵,里面只有4个1,4个2,4个3,4个4,问能否在5步内将矩阵恢复成每列相同或每行相同。
思路:直接对给出的矩阵进行dfs,深度从1开始枚举到5即可。改变矩阵写起来比较麻烦不知道有没有什么更好的办法。
#include<bits/stdc++.h>
using namespace std;
int mp[5][5];
bool judge()//判断矩阵是否每列相同或每行相同
{
bool f1=true,f2=true;
for(int i=1;i<=4;i++)
{
for(int j=2;j<=4;j++)
if(mp[i][j]!=mp[i][1]){f1=false;break;}
if(!f1)break;
}
if(f1)return true;
for(int i=1;i<=4;i++)
{
for(int j=2;j<=4;j++)
if(mp[j][i]!=mp[1][i]){f2=false;break;}
if(!f2)break;
}
return f2;
}
void rote(int dir,int xb,int fx)//改变矩阵,共16种策略,dir表示行或列,xb表示第几行或第几列,fx表示正或反
{
if(dir)
{
if(fx)
{
int tp=mp[1][xb];
for(int i=1;i<=3;i++)mp[i][xb]=mp[i+1][xb];
mp[4][xb]=tp;
}
else
{
int tp=mp[4][xb];
for(int i=4;i>1;i--)mp[i][xb]=mp[i-1][xb];
mp[1][xb]=tp;
}
}
else
{
if(fx)
{
int tp=mp[xb][1];
for(int i=1;i<=3;i++)mp[xb][i]=mp[xb][i+1];
mp[xb][4]=tp;
}
else
{
int tp=mp[xb][4];
for(int i=4;i>1;i--)mp[xb][i]=mp[xb][i-1];
mp[xb][1]=tp;
}
}
}
bool dfs(int step)
{
if(step==0)
{
if(judge())return true;
else return false;
}
bool ret=0;
for(int i=1;i<=4;i++)//枚举第几行或第几列
{
rote(0,i,0);
if(dfs(step-1))ret=1;
rote(0,i,1);
rote(0,i,1);
if(dfs(step-1))ret=1;
rote(0,i,0);
rote(1,i,0);
if(dfs(step-1))ret=1;
rote(1,i,1);
rote(1,i,1);
if(dfs(step-1))ret=1;
rote(1,i,0);
}
return ret;
}
int main()
{
int t;
scanf("%d",&t);
for(int ca=1;ca<=t;ca++)
{
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
scanf("%d",&mp[i][j]);
int ans=-1;
for(int i=0;i<=5;i++)//枚举深度
{
if(dfs(i)){ans=i;break;}//如果搜到了就退出循环
}
printf("%d\n",ans);
}
return 0;
}