输入输出格式
输入格式:
第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。
输出格式:
对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。
输入输出样例
输入样例#1:
2
10110
10110
10110
01
∗
11
01*11
01∗11
10111
10111
10111
01001
01001
01001
00000
00000
00000
01011
01011
01011
110
∗
1
110*1
110∗1
01110
01110
01110
01010
01010
01010
00100
00100
00100
输出样例#1:
7
-1
这道题是cdcq出的考试题qwq,刚看到这道题的时候除了普通搜索还真没想到其他的算法(因为没见过QAQ)
可能考试的时候比较懵打了一个贼复杂的dfs…
还没调出来-.-
下午就知道是IDA*0.0
这道题中,由于步数限制给的很明确,所以迭代加深还是能比较明显的看出来的,
但就算是迭代加深这1s的时间也不够用,而且还没有啥好的剪枝。
于是我们可能就会感叹:要是代码跟我脑子一样自我判断就好了0.0
然后就出现了搜索中的估价函数
估价函数就类似于模拟自己在决策时影响自己判断的因素,首先要证明这些因素满足条件时一定能得到正确答案,然后把他们写成函数以影响自己的搜索(emm这么说会不会有点抽象)
就是把自己手推样例时所想的判断方法写在程序里。
然后在判断是否继续搜索时加上这个条件
这道题很容易想到我们自己在判断时是尽量把不合法的棋子往合法的地方移动
因此就用当前状态与目标状态不匹配的格子作为估价函数
判断条件就用当前步数+不匹配格数
且因为当估价函数为零时的状态一定是目标状态,所以这个策略一定是合法的。
然后就是看了才能懂我刚才在说什么的代码
#include<bits/stdc++.h>
using namespace std;
int goal[5][5] = {{1, 1, 1, 1, 1}, {0, 1, 1, 1, 1,}, {0, 0, 2, 1, 1}, {0, 0, 0, 0, 1}, {0, 0, 0, 0, 0}};
int mp[5][5], t, pd;
int dx[8] = {1, -1, 2, -2, 1, -1, 2, -2};
int dy[8] = {2, 2, -1, -1, -2, -2, 1, 1};
int tx, ty;
int g(){
int ret = 0;
for(int i = 0; i < 5; ++i)
for(int j = 0; j < 5; ++j)
if(mp[i][j] != goal[i][j]) ++ret;
return ret;
}
bool IDA(int maxd, int d, int x, int y){
if(!g()) return 1;
if(g() + d - 1 > maxd) return 0;
for(int i = 0; i < 8; ++i){
int x1 = x + dx[i], y1 = y + dy[i];
if(x1 < 0 || x1 > 4 || y1 < 0 || y1 > 4) continue;
swap(mp[x1][y1], mp[x][y]);
if(IDA(maxd, d + 1, x1, y1)) return 1;
swap(mp[x1][y1], mp[x][y]);
}
return 0;
}
int main()
{
scanf("%d", &t);
while(t--){
pd = 0;
for(int i = 0; i < 5; ++i){
char s[5]; scanf("%s", s);
for(int j = 0; j < 5; ++j){
if(s[j] - '0' == 0) mp[i][j] = 0;
else if(s[j] - '0' == 1) mp[i][j] = 1;
else mp[i][j] = 2, tx = i, ty = j;
}
}
for(int i = 1; i <= 15; ++i)
if(IDA(i, 0, tx, ty)){
pd = i; break;
}
if(pd) printf("%d\n", pd);
else puts("-1");
}
return 0;
}