POJ-1324(A*+状态压缩)

来源:互联网 发布:西门子840d编程指令 编辑:程序博客网 时间:2024/05/17 12:07

真是好题啊,各种TLE之后看了人家的解题报告才A的:

(1)一开始用deque保存状态信息,用queue进行BFS,TLE

(2)试图用数组保存状态信息,自己写队列进行BFS,还是TLE

(3)由于row和col都小于20,试图用5*2个bit表示一个位置,还是TLE

终于看了discuss,找到了大牛的解题报告:http://blog.csdn.net/legedexinshi/article/details/37761761,原来要用相对位置保存状态啊,真是高贵的一逼啊,竟然12个bit就能保存除了头部意外的所有信息了呢,参考了上述解题报告的思想,终于125ms A了(大牛的题解是32ms,在状态处理上我的貌似慢些),总之第一道A*真是一把辛酸泪啊:


#include <cstdio>#include <cstring>#include <queue>using namespace std;const short dir[4][2] ={    {-1, 0},//up    {1,  0},//down    {0, -1},//left    {0,  1}//right};inline short getDir(short r, short c, short nr, short nc){    return r == nr ? (c < nc ? 3 : 2) : (r < nr ? 1 : 0);}int N, M, L, K;char map[21][21];//map[r][c] = 1 means (r,c) is blocked else it's vacantinline bool unreachable(int nr, int nc){    return nr < 1 || nr > N || nc < 1 || nc > M || map[nr][nc];}short dis[21][21]; //dis[r][c] record absolute BFS distance to (1,1) positionshort head, tail, q[21*21*2];const short mask[] = {    0x0003 << 0,    0x0003 << 2,    0x0003 << 4,    0x0003 << 6,    0x0003 << 8,    0x0003 << 10,    0x0003 << 12};struct Snake{    short r, c;//snake head's position    short body;//use 2 bit to record relative position between body[i] and body[i+1]               //thus only body[13:0] is valid    short step;//how many steps already taken    bool operator < (const Snake& other)const{        return step + dis[r][c] > other.step + dis[other.r][other.c];    }    bool isPart(short nr, short nc)const{        short pr = r, pc = c, cr, cc, d;        for(int i = 0; i + 1 < L; ++i){            d = (body & mask[i]) >> (i<<1);            cr = pr + dir[d][0];            cc = pc + dir[d][1];            if(cr == nr && cc == nc) return true;            pr = cr;            pc = cc;        }        return false;    }} initial;priority_queue<Snake> pq;short leastStep[21][21][1<<14];bool input(){    scanf("%d%d%d", &N, &M, &L);    if(!N) return false;        short r, c, nr, nc;    scanf("%hd%hd", &r, &c);    initial.r = r;    initial.c = c;    initial.body = 0;    initial.step = 0;    for(int i = 1; i < L; ++i){        scanf("%hd%hd", &nr, &nc);        initial.body |= getDir(r, c, nr, nc) << ((i-1)<<1);        r = nr;        c = nc;    }        scanf("%d", &K);    memset(map, 0, sizeof(map));    for(int i = 0; i < K; ++i){        scanf("%hd%hd", &r, &c);        map[r][c] = 1;    }    return true;}void BFS(){    head = tail = 0;    memset(dis, -1, sizeof(dis));    dis[1][1] = 0;    q[tail++] = 1; q[tail++] = 1;        short level = 0;    while(head != tail){        ++level;        for(short n = (tail-head)>>1; n; --n){//same level            short r = q[head++], c = q[head++], nr, nc;            for(int i = 0; i < 4; ++i){                nr = r + dir[i][0];                nc = c + dir[i][1];                if(unreachable(nr, nc) || dis[nr][nc] != -1) continue;                dis[nr][nc] = level;                q[tail++] = nr;                q[tail++] = nc;            }        }    }}short AStar(){    while(!pq.empty()) pq.pop();        for(int i = 1; i <= N; ++i){        for(int j = 1; j <= M; ++j) memset(leastStep[i][j], -1, (1<<14)*sizeof(short));    }    leastStep[initial.r][initial.c][initial.body] = 0;    pq.push(initial);        Snake now, nex;    while(!pq.empty()){        now = pq.top(); pq.pop();        for(int i = 0; i < 4; ++i){            nex.r = now.r + dir[i][0];            nex.c = now.c + dir[i][1];            if(unreachable(nex.r, nex.c) || now.isPart(nex.r, nex.c)) continue;            if(nex.r == 1 && nex.c == 1) return now.step + 1;        //remove tail and head become second joint            nex.body = (now.body & 0x0FFF)<<2 | (i^1);            nex.step = now.step + 1;            short& best = leastStep[nex.r][nex.c][nex.body];            if(best == -1 || best > nex.step){                best = nex.step;                pq.push(nex);            }        }    }    return -1;}int main(){    for(int test = 1; input(); ++test){        if(initial.r == 1 && initial.c == 1) printf("Case %d: 0\n", test);        else{            BFS();            if(dis[initial.r][initial.c] == -1) printf("Case %d: -1\n", test);            else printf("Case %d: %hd\n", test, AStar());        }    }    return 0;}

0 0