洛谷

为什么估价是16,因为最后一步复原空格可以恢复两个位置,当然设成17、18都可以。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;


struct State {
    char g[5][6];                   //矩阵的状态,0是白马,1是黑马,规定空格是*
    int hstep;                      //step+估价函数,至少需要的步数

    State() {}
    int h();                        //估价函数h,为未归位的骑士数
    void move_to(int id,int step);  //尝试移动状态加入优先队列

    bool operator==(const State& s)const {
        //无序map
        for(int i=0; i<5; i++)
            for(int j=0; j<5; j++)
                if(g[i][j]!=s.g[i][j])
                    return false;
        return true;
    }

    bool operator<(const State& s)const {
        //最大堆
        return hstep>s.hstep;
    }

} s_state,t_state;

struct State_Hash {
    size_t operator()(const State&t)const {
        int id=0;
        for(int i=0; i<5; i++)
            for(int j=0; j<5; j++)
                id=(id<<1)+(t.g[i][j]-'0');
        return id;
    }
};

int State::h() {
    //估价函数,因为每次移动的是空格
    int res=0;
    for(int i=0; i<5; i++)
        for(int j=0; j<5; j++)
            if(g[i][j]!=t_state.g[i][j])
                res++;
    return res;
}


//vis从起点开始找到的状态
unordered_map<State,int,State_Hash> vis;
priority_queue<State> pq;

int dx[]= {2,1,-1,-2,-2,-1,1,2};
int dy[]= {1,2,2,1,-1,-2,-2,-1};


void State::move_to(int id,int step) {
    //空格向id方向移动
    int ox=-1;
    int oy=-1;

    for(int i=0; i<5; i++) {
        for(int j=0; j<5; j++) {
            if(g[i][j]=='*') {
                ox=i,oy=j;
                break;
            }
        }
    }

    int nx=ox+dx[id];
    int ny=oy+dy[id];

    //越界
    if(nx<0||ny<0||nx>4||ny>4)
        return;

    State res=*this;
    swap(res.g[ox][oy],res.g[nx][ny]);

    res.hstep=step+1+res.h();

    if(hstep>16)
        return;

    if(vis.count(res)) {
        return;
    } else {
        vis[res]=step+1;
        pq.push(res);
    }
}



//单向A*搜索
bool A_star() {
    vis.clear();
    while(!pq.empty())
        pq.pop();

    vis[s_state]=0;
    pq.push(s_state);
    while(!pq.empty()) {
        State curstate=pq.top();
        pq.pop();
        int curstep=vis[curstate];
        for(int i=0; i<8; i++)
            curstate.move_to(i,curstep);
        if(vis.count(t_state))
            return true;
    }
    return false;
}



int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    strcpy(t_state.g[0],"11111");
    strcpy(t_state.g[1],"01111");
    strcpy(t_state.g[2],"00*11");
    strcpy(t_state.g[3],"00001");
    strcpy(t_state.g[4],"00000");;

    int T;
    scanf("%d",&T);
    while(T--) {
        for(int i=0; i<5; i++)
            scanf("%s",s_state.g[i]);

        if(A_star()) {
            int ans=vis[t_state];
            printf("%d
",ans>15?-1:ans);
        } else {
            puts("-1");
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Yinku/p/10978329.html