迭代加深dfs优化

当普通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;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值