[USACO12OPEN]Unlocking Block【BFS / 广搜】

Pro

Luogu3053

Sol

真的只是一个 B F S !!!一个氧气都救不了的程序(快读+快写还 T L E 了一个点)

大体思路:对于每一种状态,我们枚举三个模块是否可以向左向右向上向下移动,如果可以移动,入队,继续搜索,队列中存整张图。处理方法:对于队列中的图,不需要每一个点都存储。在输入的时候,我们可以根据点之间的相对位置求出这个模块的形状,存起来,这样队列中只需要对每一个模块存一个位置就可以,我们把这个位置叫做模块的代表点,这样就能推出其他的位置。

关键的地方在于如何判断是否已经入过队。用集合配合类似哈希来处理,因为我们存储的只有三个点,六个值,第一感觉就是六维数组,然而六维数组会 M L E 。为什么呢?因为我们存储的不只是一个 10 × 10 的矩阵,而是 30 × 30 ,我们也需要把看不到的地方存起来,这样的六维数组会变得很大,因此会 M L E

因为我们只是存了六个数,即三个模块的代表点的横纵坐标,所以就可以将这六个值哈希为一个六位数的值,放入集合,(突然想到这里好像可以用一位数组,请自行尝试)。

还需要两个很长很长的判断,一个是判断当前状态是否就是答案,另一个是每一个模块的每一个方向是否可以移动。这两个判断还是很好写的,不多说了。

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<set>
#include<cstring>
using namespace std;

struct Node {
    int x , y;
};
Node shape[5][105] , sta[5];
struct Que {
    Node n[4];
    int cnt;
    Que(){};
    Que(Node nn1 , Node nn2 , Node nn3 , int ccnt) {
        n[1] = nn1 , n[2] = nn2 , n[3] = nn3 , cnt = ccnt;
    }
};
set<int>s;
queue<Que>q;
int n[4] , dx[4] = {0,0,-1,1} , dy[4] = {1,-1,0,0};
inline int mymin(int a , int b) { return a<b?a:b; }
inline int mymax(int a , int b) { return a>b?a:b; }

void read(int &x)
{
    char c = getchar(); x = 0;
    while(c < '0' || c > '9') c = getchar();
    while(c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
}

void put(int x)  
{  
    int num = 0; char c[15];
    while(x) c[++num] = (x%10)+48, x /= 10;
    while(num) putchar(c[num--]);
    putchar('\n'); 
}

int jud(Que x) {
    int hin[4] , hax[4] , zin[4] , zax[4] , map[35][35];
    memset(map , 0 , sizeof(map));
    for(int i=1; i<=3; i++) {
        hin[i] = zin[i] = 0x3f;
        hax[i] = zax[i] = 0;        
    }
    for(int i=1; i<=3; i++)
        for(int j=1; j<=n[i]; j++) {
            int xx , yy;
            xx = x.n[i].x + shape[i][j].x;
            yy = x.n[i].y + shape[i][j].y;
            hin[i] = mymin(hin[i] , xx);
            hax[i] = mymax(hax[i] , xx);
            zin[i] = mymin(zin[i] , yy);
            zax[i] = mymax(zax[i] , yy);
        }
    for(int i=1; i<=3; i++)
        for(int j=zin[i]; j<=zax[i]; j++)
            for(int k=hin[i]; k<=hax[i]; k++) {
                if(map[j+10][k+10])
                    return 0;
                map[j+10][k+10] = 1;    
            }
    return 1;
}

int mov(int x , int d , Que t) {
    int map[35][35];
    memset(map , 0 , sizeof(map));
    for(int i=1; i<=3; i++) {
        if(i == x) {
            t.n[i].x += dx[d];
            t.n[i].y += dy[d];
        }
        for(int j=1; j<=n[i]; j++) {
            int xx , yy;
            xx = t.n[i].x + shape[i][j].x;
            yy = t.n[i].y + shape[i][j].y;
            if(map[xx+10][yy+10])
                return 0;
            map[xx+10][yy+10] = 1;
        }
    }
    return 1;
}

void update(int &a , Que b) {
    a = b.n[1].x*100000+b.n[1].y*10000+b.n[2].x*1000+b.n[2].y*100+b.n[3].x*10+b.n[3].y;
}

int main() {
    read(n[1]) , read(n[2]) , read(n[3]); 
    for(int i=1; i<=3; i++) {
        Node a;
        read(a.x) , read(a.y);
        sta[i] = a;
        shape[i][1] = (Node){0,0};
        for(int j=2; j<=n[i]; j++) {
            int x , y;
            read(x) , read(y);
            shape[i][j] = (Node){x-a.x,y-a.y};
        }
    }
    q.push(Que(sta[1],sta[2],sta[3],0));
    s.insert(sta[1].x*100000+sta[1].y*10000+sta[2].x*1000+sta[2].y*100+sta[3].x*10+sta[3].y);
    while(!q.empty()) {
        Que u = q.front() , v;
        q.pop();
        if(jud(u)) {
            put(u.cnt);
            return 0;
        }
        u.cnt++;
        for(int i=0; i<4; i++)
            for(int j=1; j<=3; j++)
                if(mov(j,i,u)) {
                    v = u;
                    Node t;
                    int m;
                    t.x = v.n[j].x + dx[i];
                    t.y = v.n[j].y + dy[i];
                    v.n[j] = t;
                    update(m,v);
                    if(s.find(m)==s.end()) {
                        s.insert(m);
                        q.push(v);
                    }
                }
    }
    printf("-1");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43061009/article/details/82426167