搜索~贪吃蛇简化

 
大意: 给你一个矩阵,有一条蛇,问蛇走到(1,1)点所需要的步骤数,有石块障碍
 
思路:
    被这道题的状态如何标记折磨了两天~,后来看老师讲稿,队里大牛讲解终于搞懂了; 蛇的长度[1,8]。矩阵大小不超过20*20。蛇头的每一次移动蛇身就会跟着移动,所以一般的在地图标记蛇身的一节需要[21][21]数组, 蛇身最长有8节,也就是16维数组。怎么开的了。。。。
优化标记状态:(这想法妙~)
蛇相连的两节之间的X,Y之差只有四种可能:(0,1) (-1,0) (0,-1) (1,0) 给它们都+1 就成了一个[3][3]数组完全放的下,然后记+1后的 [0][1]=0; [1][0]=1; [1][2]=2; [2][1]=3; 就可以用四进制来表示蛇的最大状态不会超过 3*(4^8) < (10^6) 这样就可以接受了~及标记状态数组只要[21][21][10^6]  就ok~~~~
 
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN = 16384;
const int MAX = 5000000;
struct node
{
    int x[8][2];
    int step;
} Q[MAX];
bool map[21][21], v[21][21][MAXN];
int t[3][3];     //对于状态的压缩所用的数组
int dir[4][2] = {0, 1, -1, 0, 0, -1, 1, 0};
int n, m, l;
int BFS(int len[8][2])
{
    int front=0, last=0;  //模拟循环队列头尾
    int x, y, i, j, sum;
    x=len[0][0];
    y=len[0][1];
    for(sum=0, i=1; i<l; i++)
    {
        sum = sum*4+t[x-len[i][0]+1][y-len[i][1]+1];
        x = len[i][0];
        y = len[i][1];
    }
    v[len[0][0]][len[0][1]][sum]=true; //标记起始位置
    for(i=0; i<l; i++)
    {
        Q[last].x[i][0]=len[i][0];
        Q[last].x[i][1]=len[i][1];
    }
    Q[last].step=0;
    last = (last+1) % MAX;
    while(front!=last)
    {
        if(Q[front].x[0][0]==1 && Q[front].x[0][1]==1) //到达目标
            return Q[front].step;
        for(i=0; i<4; i++)
        {
            x = Q[front].x[0][0] + dir[i][0];
            y = Q[front].x[0][1] + dir[i][1];
            if(x<1 || x>n || y<1 || y>m) continue; //越界
            int flag=0;             //判断是否为本身 flag为标记
            for(j=0; j<l; j++)
                if(x==Q[front].x[j][0] && y==Q[front].x[j][1])
                {
                    flag=1;
                    break;
                }
            if(map[x][y] || flag) continue;   //石头或者本身
            int tx=x, ty=y;
            for(sum=0, j=0; j<l-1; j++)
            {
                sum = sum*4+t[tx-Q[front].x[j][0]+1][ty-Q[front].x[j][1]+1];
                tx = Q[front].x[j][0];
                ty = Q[front].x[j][1];
            }
            if(v[x][y][sum]) continue; //新的位置是否被标记过
            v[x][y][sum] = true;
            Q[last].x[0][0]=x;
            Q[last].x[0][1]=y;
            for(j=1; j<l; j++)         //更新蛇身
            {
                Q[last].x[j][0]=Q[front].x[j-1][0];
                Q[last].x[j][1]=Q[front].x[j-1][1];
            }
            Q[last].step = Q[front].step+1;
            last=(last+1)%MAX;        //修改指针
           } 
        front=(front+1)%MAX;
    }
    return -1;
}
int main()
{
    int cas=1, i, j, k, len[8][2];
    t[0][1]=0;
    t[1][0]=1;
    t[1][2]=2;
    t[2][1]=3; //对于x,y坐标的差值各自+1 就有这四种结果
    while(scanf("%d%d%d", &n, &m, &l)&& n && m && l)
    {
        for(i=1; i<=n; i++)
            for(j=1; j<=m; j++)
            {
                map[i][j]=false;
                for(k=0; k<=MAXN; k++)
                    v[i][j][k]=false;
            }
        for(i=0; i<l; i++)
            scanf("%d%d", &len[i][0], &len[i][1]);
        scanf("%d", &k);
        while(k--)
        {
            scanf("%d%d", &i, &j);
            map[i][j]=true;
        }
        k = BFS(len);
        printf("Case %d: %d\n", cas++, k);
    }
    return 0;
}

 

posted @ 2015-09-22 16:53  马晨  阅读(134)  评论(0)    收藏  举报