bzoj1085: [SCOI2005]骑士精神

6 篇文章 0 订阅
1 篇文章 0 订阅

题面在这里

题意:

有一个5*5的01阵,有一个位子是空用*表示。每个0或1都可以走马步到空格子。
现在给一个初始的矩阵,要变成下面这个状态。
11111
01111
00*11
00001
00000
问最少的步数。若超过15步则输出-1.

做法:

一开始打了一个状压bfs。然后光荣地没跑过样例= =
正解是A*。观察到有一个条件叫做超过15步就输出-1,于是我们可以1~15枚举步数,这样限定了dfs的深度,最多dfs15层,就会快很多。
另外加一些小优化,比如当前步数加上还需走的步数超过枚举的k的话就不用再继续走了(肯定不优)。

代码:

/*************************************************************
    Problem: bzoj 1085 [SCOI2005]骑士精神
    User: fengyuan
    Language: C++
    Result: Accepted
    Time: 552 ms
    Memory: 1292 kb
    Submit_Time: 2018-01-17 13:19:48
*************************************************************/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<map>
#include<queue>
#define id(x, y) (((x)-1)*5+(y))
using namespace std;
typedef long long ll;

const int N = 7;
const int dx[8] = {-2, -2, -1, 1, 2, 2, 1, -1};
const int dy[8] = {-1, 1, 2, 2, 1, -1, -2, -2};
const int b[6][6] = {
    {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}
};
char s[10];
int a[N][N], k, sx, sy;
bool flg;
struct node{
    ll sta; int step;
    node() {}
    node(ll x, int y) { sta = x, step = y; }
};

inline bool ok(int x, int y) { return x >= 1 && x <= 5 && y >= 1 && y <= 5; }
inline bool check(int a[7][7])
{
    for(int i = 1; i <= 5; i ++)
        for(int j = 1; j <= 5; j ++) if(a[i][j] != b[i][j]) return 0;
    return 1;
}
inline int cal(int a[7][7])
{
    int ret = 0;
    for(int i = 1; i <= 5; i ++)
        for(int j = 1; j <= 5; j ++) ret += a[i][j] != b[i][j];
    return ret;
}
inline void dfs(int step, int a[7][7], int x, int y)
{
    if(step == k) { if(check(a)) flg = 1; return; }
    if(flg) return;
    for(int i = 0; i < 8; i ++) {
        int xx = x+dx[i], yy = y+dy[i];
        if(!ok(xx, yy)) continue;
        swap(a[xx][yy], a[x][y]);
        if(cal(a) + step <= k) dfs(step+1, a, xx, yy);
        swap(a[xx][yy], a[x][y]);
    }
}
int main()
{
    int test; scanf("%d", &test);
    while(test --) {
        for(int i = 1; i <= 5; i ++) {
            scanf("%s", s+1);
            for(int j = 1; j <= 5; j ++) {
                a[i][j] = s[j]-'0';
                if(s[j] == '*') a[i][j] = 2, sx = i, sy = j;
            }
        }
        flg = 0;
        for(k = 1; k <= 15; k ++) {
            dfs(0, a, sx, sy);
            if(flg) { printf("%d\n", k); break; }
        }
        if(!flg) puts("-1");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值