洛谷P2324 bzoj1085 [SCOI2005]骑士精神

P2324 [SCOI2005]骑士精神

题目描述

输入输出格式

输入格式:

第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。

 

输出格式:

对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。

 

输入输出样例

输入样例#1: 复制
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
输出样例#1: 复制
7
-1

说明

 

这道题是一道很好的搜索题 结合了迭代加深搜索还有$A*$

考虑到枚举棋子走法很麻烦 并且只有一个空格 所以考虑到走空格 每次有$8$种走法 开个增量数组搞一搞就可以了

迭代加深首先肯定是枚举走的最多的次数 然而这个玩意还是要T

所以使用$A*$估价函数 怎么估呢

考虑到每次移动空格至多使一个棋子走到目标位置 所以统计有多少棋子不在正确的位置上 这就是最少步数

如果最少步数加上当前步数超界就返回

代码

#include <bits/stdc++.h>
#define oo 1e9
using namespace std;

int n, tag, T, x, y, s[10][10], G[10][10];
int zl[8][2] = {{-2,-1},{-1,-2},{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1}};
char h[10];
int g[10][10] = {{0,0,0,0,0,0},
                 {0,1,1,1,1,1},
                 {0,0,1,1,1,1},
                 {0,0,0,2,1,1},
                 {0,0,0,0,0,1},
                 {0,0,0,0,0,0}
};

void init( ) {
    
    for(int i = 1;i <= 5;i ++) {
        for(int j = 1;j <= 5;j ++) s[i][j] = G[i][j];
    }
}

bool check( ) {
    
    for(int i = 1;i <= 5;i ++)
        for(int j = 1;j <= 5;j ++) {
            if(i == j) {
                if(i <= 2) if(s[i][j] != 1) return false;
                if(i == 3) if(s[i][j] != 2) return false;
                if(i >= 4) if(s[i][j] != 0) return false;
            }
            if(i < j && s[i][j] != 1) return false;
            if(i > j && s[i][j] != 0) return false;
        }
    return true;
}

int eval( ) {
    
    int cnt = 0;
    for(int i = 1;i <= 5;i ++)
        for(int j = 1;j <= 5;j ++) {
            if(s[i][j] != g[i][j] && s[i][j] != 2) cnt ++;
        }
    return cnt;
}

void dfs(int step, int lim, int x, int y) {
    
    if(step == lim) {
        if(check( )) tag = min(tag, step);
        return ;
    }
    int res = eval( );
    if(step + res > lim) return ;
    if(check( )) {tag = min(tag, step); return ;}
    for(int i = 0;i < 8;i ++) {
        int xx = x + zl[i][0], yy = y + zl[i][1];
        if(xx > 5 || xx < 1 || yy < 1 || yy > 5) continue;
        swap(s[x][y], s[xx][yy]);
        dfs(step + 1, lim, xx, yy);
        swap(s[x][y], s[xx][yy]);
    }
}

void Solve( ) {
    
    scanf("%d",& T);
    while(T --) {
        for(int i = 1;i <= 5;i ++) {
            scanf("%s",h + 1);
            for(int j = 1;j <= 5;j ++) {
                if(h[j] == '0') G[i][j] = 0;
                else if(h[j] == '1') G[i][j] = 1;
                else {
                    G[i][j] = 2; x = i, y = j;
                }
            }
        }
        tag = oo; init( );
        for(int i = 0;i <= 15;i ++) {
            //init( );
            dfs(0, i, x, y);
            if(tag != oo) {
                printf("%d\n", i); break;
            }
        }
        if(tag == oo) printf("-1\n");
    }
}

int main( ) {
    
    Solve( );
}
posted @ 2018-10-10 20:55  阿澈说他也想好好学习  阅读(127)  评论(0编辑  收藏  举报