有一段日子木有更新solution神马的,北京区域赛的准备工作好烦哪。强烈要求出现一个组委会,而不是我们这帮集训队的来干各种奇葩活。
言归正传,9月的浙大月赛可搞题颇多,场上就想写这题,可惜木有机时,只能场下写咯。可惜一写就掉坑里了,直到现在才爬出来,好恶心的一道题啊。
题意:
10*10的棋盘,有一个你控制的棋子A,每步可四向移动;有一个镜像棋子B,和你呈镜像运动,遇边、石则当前回合不动;路上有石头,不可入;有压路机,循环运动,遇神杀神,遇石回头;地图上有<=5个宝石,你需要用A去拾取全部(WA点1,用A拾取,B没用);有两个出口,需要让A、B同时到达这俩出口,且拿满宝石,则你赢了。被压路机压到A、B或者同时到达出口时宝石没拿满,都是死。
做法:
就是BFS+模拟,模拟的规则略复杂。
先说状态,压路机方向 + 压路机位置 + A位置 + B位置 + 五块宝石的拿取状态。最后一个状态我用2^5来存,所以整体是一个9位数(虽说大牛们说前两个状态因为压路机的循环移动性质乘起来只有20种)。整体状态数=2 * 10 * 100 * 100 * 32 = 6400000 ,果断hash。一开始用MAP,TLE了;后来只能手写hash了,不仅要记hash之前的状态值还需要记对应状态的权值,难怪那么大内存。
接着就是模拟了:
每次解hash(注意hash数字时候的顺序)得取当前状态,然后算出下一回合A、B、压路机K的位置和宝石状态。
但是判定非法的时候,需要按顺序判断:
因为走的顺序是A、B、K,所以先判断A,check(超范围、碰R),碰K(未动),碰B,碰到则状态非法;再判断B,若碰新A,check,碰K,则不动。先不判K。
然后判断A是否拿到了新的宝石。
此时要判断A、B是否达到了出口,如果达到了而宝石不齐,则状态非法(wa点2);若齐了,则更新最短路长(不要在出队以后再更新,要在入队前更新,否则压路机会把这种情况给判非法掉)。只要达到出口,则状态不进队。
最后判K,吃了A或者B则状态非法。(WA点3)
代码写的好矬啊,别人800ms过,我wa+tle了两版才2400ms过。。。蒟蒻伤不起啊。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;
#define maxn 11
#define hashsize (6400013)
#define maxm (hashsize + 10)
int ans;
const int inf = 1 << 30;
char mst[maxn][maxn];
int vis[maxm];
int cas;
int tot;
struct HASH
{
    int x,step;
    HASH(){}
    HASH(int _x,int _s):x(_x),step(_s){}
}h[maxm];
inline int find(int x)
{
    int z = x % hashsize;
    return vis[z] == cas?h[z].step:-1;
}
inline void insert(int x,int value)
{
    int z = x % hashsize;
    vis[z] = cas;
    h[z] = HASH(x,value);
}
inline void update(int x,int value)
{
    int z = x % hashsize;
    h[z].step = value;
}
struct node
{
    int x,y;
    node(){}
    node(int a,int b):x(a),y(b){}
    bool operator ==(const node p)
    {
        return x == p.x && y == p.y;
    }
}pa,pb,en[2],ki,pc[6];
int r,c;
int pcs;
char dir;
int dx[] = {-1,1,0,0};
int dy[] = {0,0,-1,1};
char rd[] = {'N','S','W','E'};
int co(char _d)
{
    for(int i = 0;i < 4;i++)
        if(rd[i] == _d)
            return i;
}
int hash(int _d,node p[],bool gd[])
{
    int x = 0;
    for(int i = 0;i < pcs;i++)
        if(gd[i])
            x |= (1 << i);
    int idx = 100;
    for(int i = 2;i >= 0;i--)
    {
        x += idx * p[i].x;
        idx *= 10;
        x += idx * p[i].y;
        idx *= 10;
    }
    x += (_d + 1) * idx;
    return x;
}
inline bool check(int x,int y)
{
    return 0 <= x && x < r && 0 <= y && y < c && mst[x][y] != 'R';
}
void bfs()
{
    queue <int> Q;
    bool gd[6];
    for(int i = 0;i < pcs;i++)
        gd[i] = true;
    node p[3];
    p[0] = ki;
    p[1] = pa;
    p[2] = pb;
    int s = hash(co(dir),p,gd);
    //cout << s << endl;
    if(find(s) == -1)
        insert(s,0);
    Q.push(s);
    //cout << s << endl;
    while(!Q.empty())
    {
        int now = Q.front();
        Q.pop();
        //cout << now << endl;
        int step = find(now);
        int idx = 100000000;
        int tdir = now / idx - 1;
        now -= (tdir+1) * idx;
        idx /= 10;
        //cout << now << endl;
        for(int i = 0;i < 3;i++)
        {
            p[i].y = now / idx;
            now -= p[i].y * idx;
            idx /= 10;
            p[i].x = now / idx;
            now -= p[i].x * idx;
            idx /= 10;
        }
        //cout << now << endl;
        int x,y;
        x = p[0].x + dx[tdir];
        y = p[0].y + dy[tdir];
        if(!check(x,y))
        {
            x = p[0].x;
            y = p[0].y;
            tdir ^= 1;
        }
        node tk = node(x,y);
        for(int i = 0;i < 4;i++)
        {
            bool dg[6] = {0};
            int ax = p[1].x + dx[i],ay = p[1].y + dy[i];
            int bx = p[2].x + dx[i^1],by = p[2].y + dy[i^1];
            if(!check(ax,ay) ||  node(ax,ay) == p[0] || node(ax,ay) == p[2])//they can stay in the same point???
                continue;
            if(!check(bx,by) || node(bx,by) == p[0] || node(bx,by) == node(ax,ay))
            {
                bx = p[2].x;
                by = p[2].y;
            }
            int what = 0;
            for(int j = 0;j < pcs;j++)
                if(((now >> j) & 1) && !(node(ax,ay) == pc[j]))
                {    
                    dg[j] = 1;
                    what |= 1 << j;
                }
            node q[3];
            q[0] = tk;
            q[1] = node(ax,ay);
            q[2] = node(bx,by);
            int ano = step + 1;
            if((en[0] == q[1] && en[1] == q[2]) || (en[0] == q[2] && en[1] == q[1]))
            {
                if(what == 0)
                    ans = min(ano,ans);
                else
                    continue;
            }
            if(q[0] == q[1] || q[0] == q[2])
                continue;
            int temp = hash(tdir,q,dg);
            int comp = find(temp);
            if(comp == -1 || comp > ano)
            {
                if(comp == -1)
                    insert(temp,ano);
                else
                    update(temp,ano);
                Q.push(temp);
            }
        }
    }
    printf("%d\n",ans == inf?-1:ans);
}
int main()
{
    cas = 0;
    while(scanf("%d %d",&r,&c) == 2)
    {
        cas++;
        int end = 0;
        pcs = 0;
        tot = 0;
        for(int i = 0;i < r;i++)
            for(int j = 0;j < c;j++)
            {
                char opt;
                scanf(" %c",&opt);
                mst[i][j] = opt;
                switch(opt)
                {
                    case 'A':
                        pa = node(i,j);
                        break;
                    case 'B':
                        pb = node(i,j);
                        break;
                    case 'K':
                        ki = node(i,j);
                        break;
                    case 'E':
                        en[end++] = node(i,j);
                        break;
                    case 'M':
                        pc[pcs++] = node(i,j);
                        break;
                }
            }
        ans = inf;
        scanf(" %c",&dir);
        bfs();
    }
}
å
backward sentence