[SCOI2005]骑士精神

\(\mathcal{\color{red}{Description}}\)

嗯,\(15\)步之内走不到就输出\(-1\).

\(\mathcal{\color{red}{Solution1}}\)

这个题是我第一次写迭代加深ORZ…没想到并不简单啊。

首先我们考虑如果移动每个不在原位子上的棋子,好像根本不可做,状态之间的关系错综复杂,所以我么考虑移动空格。

那么,我们如何来定义每一步的状态呢?我们对于搜索的每一步,记录状态\(sum\)为“还剩下多少未归位的棋子”,然后迭代加深的层数便是最开始有多少未归位的棋子数~16。这个\(16\)显然是由步数上限\(15\)得来的,\(+1\)的原因是因为我的\(code\)是在第\(n\)层搜索之前判断是否到达规定的搜索深度\(k\)

嗯,接着就要分下面几种情况来讨论:

对于下一层状态\(sum\)而言(),设现在空格的位置为\(A(x, y)\),跳一步之后到达的位置是\(A'(kx, ky)\),那么这次操作就等价于\(A\)\(A‘\)位置的互换。

1、如果换位之前,\(A’\)和正确的矩阵中\(A'\)的颜色一致,但是\(A\)的颜色和正确矩阵中的\(A’\)位置颜色也相同,那换了和没换没有区别,所以并不考虑这一点。

2、如果换位之前,\(A’\)和正确的矩阵中\(A'\)的颜色一致,但是\(A\)的颜色和正确矩阵中的\(A’\)位置颜色不相同,那换了之后未归位数就会变多,所以\(sum \ \ ++\)

if (now[kx][ky] == rht[kx][ky] && now[kx][ky] != rht[x][y]) sum ++ ;

3、如果换位之前,\(A’\)和正确的矩阵中\(A'\)的颜色不一致,但是\(A\)的颜色和正确矩阵中的\(A’\)位置颜色相同,那换了之后未归位数就会变少,所以\(sum \ \ --\)

if (now[kx][ky] != rht[kx][ky] && now[kx][ky] == rht[x][y]) sum -- ;

4、如果下一步走到了空格上,那么说明有空格归位了,$sum \ \ -- $

        if (rht[kx][ky] == -1) sum -- ;

5、如果这一步走到了空格,那么下一步就势必要多一个未归位的,所以\(sum \ \ ++\)

        if (rht[x][y] == -1) sum ++ ;

嗯,唐子川大佬给我讲的qwq。

那么看起来好像比\(5 \times 5\)的枚举快多了,但我并不知道到何时我才会有这种素养让我能想出这种剪枝\(QAQ\).

// luogu-judger-enable-o2
//Flower学习专用 
#include<cstdio>
#include<iostream>
#define rep(i, a, b) for(int i = a; i <= b; i ++)

using namespace std ;
bool mark = 0;
char k ;
int mp = 0, max_deep, T, stx, sty, i, kk;
int fx[8]={-2,-2,-1,1,-1,1,2,2},
    fy[8]={-1,1,2, 2,-2,-2,-1,1};
int now[6][6], rht[6][6] = { {},
                            {0, 1, 1, 1, 1, 1},
                            {0, 0, 1, 1, 1, 1},
                            {0, 0, 0, -1, 1, 1},
                            {0, 0, 0, 0, 0, 1},
                            {0, 0, 0, 0, 0, 0},
                           };
bool knight(int step, int left, int last, int x, int y){
    if (step + left > max_deep) return 0;
    if (!left) return 1 ;
    int kx, ky;
    int j ;
    rep (j, 0, 7){
        if (j == 7 - last) continue ;
        kx = x + fx[j] ;
        ky = y + fy[j] ;
        int lleft = left ;
        if(kx < 1 || ky < 1 || kx > 5 || ky > 5) continue ;
        if (now[kx][ky] == rht[kx][ky] && now[kx][ky] != rht[x][y]) lleft ++ ;
        if (now[kx][ky] != rht[kx][ky] && now[kx][ky] == rht[x][y]) lleft -- ;
        if (rht[kx][ky] == -1)  lleft -- ;
        if (rht[x][y] == -1) lleft ++ ;
        swap(now[kx][ky], now[x][y]) ;
        if (knight(step + 1, lleft, j, kx, ky))  return 1 ;
        swap(now[kx][ky], now[x][y]) ;
    }
    return 0 ;
}
int main(){
    cin >> T ;
    while(T --){
        mp = 0 ;
        mark = 0 ;
        rep(i, 1, 5)
            rep(kk, 1, 5){
                cin >> k ;
                if (k == '*') {
                    now[i][kk] = -1 ;
                    stx = i ;
                    sty = kk ;	
                }
                else now[i][kk] = k - 48;
                if(now[i][kk] != rht[i][kk]) mp ++ ;
            }
        rep(i, mp, 16){
            max_deep = i ;
            if (knight(0, mp, -1, stx, sty)){
                cout << i - 1 << endl;
                mark = 1 ;
                break ; 
            }
        }
        if(!mark) cout << -1 << endl ; 
    }
}

posted @ 2018-06-21 16:25  皎月半洒花  阅读(163)  评论(0编辑  收藏  举报