poj 1324 Astar

/*
题意:贪吃蛇,求到(1,1)的最短路径

题解:A_star搜索
感觉不完全是A*,也许有更好的做法,估价函数为(x-1+y-1),比网上说的先用BFS搜索一遍求估价值要快=。=
*/
#include <cstdio>
#include <cstring>
#include <queue>

int map[25][25];
int dir[4][2] = {-1,0,0,1,1,0,0,-1}; // 其中四个方向不可随意改变,因为在后面通过这一步来简化了一些东西

int n,m,l;

struct position
{
    int x,y;
};

struct node
{
    int x,y,depth,h;
    int body;
    bool operator < (const node &t) const
    {
        return h + depth > t.h + t.depth;
    }
};

std::priority_queue<node>Q;
int vis[21][21][1<<14];

bool is_passable(node t, int i) // 判断往i方向能否通行
{
    int nx = t.x + dir[i][0];
    int ny = t.y + dir[i][1];
    int px = t.x;
    int py = t.y;
    if (map[nx][ny] == -1) // 不是边界或者障碍物
        return false;
    for(int j=1; j<l; j++) // 判断不是身体
    {
        int c = t.body & 3;
        px -= dir[c][0];
        py -= dir[c][1];
        if (px == nx && py == ny)
            return false;
        t.body >>= 2;
    }
    return true;
}

int Astar(position head, int body)
{
    while (!Q.empty())
        Q.pop();
    node tmp;
    tmp.x = head.x;
    tmp.y = head.y;
    tmp.depth = 0;
    tmp.h = tmp.x + tmp.y - 2;
    tmp.body = body;
    memset(vis,0,sizeof(vis));
    Q.push(tmp);
    vis[tmp.x][tmp.y][tmp.body] = -1;
    while (!Q.empty())
    {
        tmp = Q.top();
        Q.pop();
        if (1 == tmp.x && 1 == tmp.y)
            return tmp.depth;
        vis[tmp.x][tmp.y][tmp.body] = -1;
        for(int i=0; i<4; i++)
        {
            if (is_passable(tmp,i))
            {
                int nx = tmp.x + dir[i][0],ny = tmp.y + dir[i][1];
                int tbody = (tmp.body << 2) & ((1 << (2*(l-1)))-1);
                tbody += i; // dir数组的四个方向已经相对应,因此可以直接加
                if (0 == vis[nx][ny][tbody]) // 已入队的即可跳过
                {
                    node vtmp;
                    vtmp.x = nx;
                    vtmp.y = ny;
                    vtmp.depth = tmp.depth + 1;
                    vtmp.h = vtmp.x + vtmp.y - 2;
                    vtmp.body = tbody;
                    vis[nx][ny][tbody] = -1;
                    Q.push(vtmp);
                }
            }
        }
    }
    return -1;
}

int main(void)
{
    int cas = 1;
    while (~scanf("%d%d%d",&n,&m,&l) && n+m+l)
    {
        position head;
        scanf("%d%d",&head.x,&head.y);
        int x,y,px,py;
        px = head.x;
        py = head.y;
        int body = 0;
        for(int i=1; i<l; i++) // body最高2位表示尾部
        {
            scanf("%d%d",&x,&y); // 0~3分别表示从该点出发往上,右,下,左可以到达前面的点
            if (x+1 == px)
                body += (2 << 2*(i-1));
            else if (x-1 == px)
                body += 0;
            else if (y+1 == py)
                body += (1 << 2*(i-1));
            else
                body += (3 << 2*(i-1));
            px = x;
            py = y;
        }

        int k;
        scanf("%d",&k);
        memset(map,0,sizeof(map));
        for(int i=1; i<=n; i++)
            map[i][0] = map[i][m+1] = -1;
        for(int i=1; i<=m; i++)
            map[0][i] = map[n+1][i] = -1;
        while (k--)
        {
            scanf("%d%d",&x,&y);
            map[x][y] = -1;
        }
        printf("Case %d: %d\n",cas,Astar(head, body));
        cas++;
    }
    return 0;
}

 

posted @ 2014-03-22 18:26  辛力啤  阅读(367)  评论(0编辑  收藏  举报