【IDA*】BZOJ1085(SCOI2005)[骑士精神]题解

来源:互联网 发布:淘宝良心的文具店 编辑:程序博客网 时间:2024/06/15 01:57

题目概述

给定一个初始状态,用最少步数变成如下图案,如果超过15步输出-1。
这里写图片描述

解题报告

先想到的是BFS,但是会发现状态数太多了,空间要炸掉。那么就想到DFS,而朴素DFS非常盲目,很可能兜圈子。BFS炸空间、DFS炸时间,让我们想到IDDFS或者IDA*(而且题目最后说答案<=15就在暗示你……),写了个IDDFS发现还是超时,那么惯用套路就是写IDA*。估价函数h(n)=不匹配个数,那么当dep(当前深度)+h(n)-1<ans(当前最大深度)的时候就可以剪枝了(h(n)-1是因为空格和马交换可能会让空格和马同时归位,所以估计代价要-1)。

示例程序

#include<cstdio>#include<algorithm>using namespace std;const int n=5;const char lst[6][6]={{},{'#','1','1','1','1','1'},{'#','0','1','1','1','1'},{'#','0','0','*','1','1'},{'#','0','0','0','0','1'},{'#','0','0','0','0','0'}};const int fl[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};int te,ans,x,y;char pic[n+5][n+5];char getrch() {char ch=getchar();while (ch!='0'&&ch!='1'&&ch!='*') ch=getchar();return ch;}int h(){    int tot=0;    for (int i=1;i<=n;i++)    for (int j=1;j<=n;j++)        tot+=pic[i][j]!=lst[i][j];    return tot;}bool check(int x,int y) {return 1<=x&&x<=n&&1<=y&&y<=n;}bool IDA_star(int dep){    if (dep+h()-1>ans) return false;    if (!h()) return true;    for (int i=0;i<=7;i++)        if (check(x+fl[i][0],y+fl[i][1]))        {            swap(pic[x][y],pic[x+fl[i][0]][y+fl[i][1]]);            x+=fl[i][0];y+=fl[i][1];            bool now=IDA_star(dep+1);            swap(pic[x][y],pic[x-fl[i][0]][y-fl[i][1]]);            x-=fl[i][0];y-=fl[i][1];            if (now) return true;        }    return false;}int main(){    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    scanf("%d",&te);    while (te--)    {        for (int i=1;i<=n;i++)        for (int j=1;j<=n;j++)        {            pic[i][j]=getrch();            if (pic[i][j]=='*') x=i,y=j;        }        for (ans=0;ans<=15&&!IDA_star(0);ans++);        if (ans<=15) printf("%d\n",ans); else printf("-1\n");    }    return 0;}
1 0
原创粉丝点击