zoukankan      html  css  js  c++  java
  • [状压DP][BFS][哈希]JZOJ 3243 Cube

    Description

    你被困在一个密室里。经过一轮摸索,你在密室里有所发现:

    1.密室是一个呈m×n网格的长方形,地面有六个格子被上了色;

    2.密室地面部分格子可能有障碍物;

    3.密室的某一格有一个六面都没上色的立方体;

    4.当立方体滚动到相邻无障碍物的格子,如果立方体接触地面的一面没有颜色而地面有颜色,则该颜色会从地面转移到立方体上;如果立方体接触地面的一面有颜色而地面没有颜色,则该颜色会从立方体转移到地面上;如果立方体接触地面的一面和地面都有颜色,则两者的颜色都不会转移。

    5.当立方体滚动到密室的指定地点,如果立方体六面都被涂上了颜色,则传送门就会开启,让你逃离这个密室。

    由于时间紧迫,你必须借助计算机的力量,算出立方体最少滚动几次就可以让你逃离这个密室。
     

    Input

    输入的第一行是用空格分隔的两个正整数m和n(2<=m<=20,2<=n<=20),分别代表密室的高和宽。接下来的m行,每行有n个字符,含义如下:

    ‘.’:该格子是空白的;

    ‘#’:该格子有障碍物;

    ‘P’:该格子是上色的;

    ‘C’:立方体就在这个格子;

    ‘G’:能让你逃离密室的指定地点。

    整个密室保证正好有6个格子是‘P’,1个格子是‘C’,1个格子是‘G’,‘.’的格子不超过12个。

    Output

    输出仅一个整数,代表立方体最少滚动的次数。我们保证每个密室场景都有解。

    对以下第一个样例,立方体最少只需要滚动10次(下右右上右右下左右左)。
     

    Sample Input

    输入1:
    2 5
    C.PPP
    PPPG.

    输入2:
    4 5
    C....
    G##.P
    .##PP
    ..PPP

    输入3:
    3 3
    PPP
    PCP
    PG.

    输入4:
    2 10
    .PPPCPPP..
    ....G.....

    Sample Output

    输出1:
    10

    输出2:
    23

    输出3:
    15

    输出4:
    21
     

    Data Constraint

    2<=m<=20,2<=n<=20

    分析

    今日最难,一个旗鼓相当的对手

    首先别被总点数迷惑了,总点数400个,但输入要求告诉我们,能走的点包括起点和终点及颜色,加起来不超过20个

    那么我们可以考虑状压,给每个点标号,状态表示哪些点有颜色

    这仅仅是图上的状态而已!因为立方体会带走颜色,所以另设一个6位状态,表示立方体当前每个面是否有颜色,建议在写的时候用记事本记着,忘掉了的话转移转死了

    两种状态需要放在一起,所以整个状态26位,后6位位立方体状态,前20位为图上状态

    然后我们考虑到,会有重复的状态,可是光是这个状态重复不够,有时图上和立方体一样,但是立方体位置不一样!

    重复的状态可用哈希加邻接表(或指针)解决

    最恶心的部分就是当你的立方体移动时,你的6位颜色状态全部要变一波,一坨位运算堆在一起

    同时注意判断一下,当颜色状态中的下面状态与当前立方体在图上位置的状态不一样(一个有颜色一个没颜色)时,需要给他们变状态

    空间别开爆了,我12Wkb刚好卡过去

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <memory.h>
    #include <queue>
    #include <cstdlib>
    using namespace std;
    const int N=4e2+10;
    const int P=388211;
    struct SS {
        int u,S;
    };
    struct QS {
        SS s;
        int dep;
    };
    struct Graph {
        int v,nx;
    }e[10000000];
    int cnt;
    int n,m;
    char c[N][N];
    int id[N][N],icnt,g[21][4];
    int sx,sy,tx,ty,sS;
    queue<QS> q;
    int p[21][517619];
    
    bool Query(SS a) {
        int i=a.S%P;
        for (int j=p[a.u][i];j;j=e[j].nx)
            if (e[j].v==a.S) return 1;
        return 0;
    }
    
    void Insert(SS a) {
        int i=a.S%P;
        e[++cnt]=(Graph){a.S,p[a.u][i]};p[a.u][i]=cnt;
    }
    
    int Roll(int S,int type) {
        switch (type) {
            case 0:return (S&48)|((S&3)<<2)|((S&4)>>1)|((S&8)>>3);
            case 1:return (S&48)|((S&1)<<3)|((S&2)<<1)|((S&12)>>2);
            case 2:return ((S&3)<<4)|(S&12)|((S&16)>>3)|((S&32)>>5);
            case 3:return ((S&1)<<5)|((S&2)<<3)|(S&12)|((S&48)>>4);
        }
    }
    
    void Solve(int u,int bS,int cS,int dep) {
        if ((cS&1)^((bS>>u-1)&1)) cS^=1,bS^=(1<<u-1);
        if (!bS&&u==id[tx][ty]) {
            printf("%d",dep-1);
            exit(0);
        }
        int S=bS|(cS<<icnt);
        if (Query((SS){u,S})) return;
        q.push((QS){(SS){u,S},dep});
        Insert((SS){u,S});
    }
    
    void BFS() {
        q.push((QS){(SS){id[sx][sy],sS},1});
        Insert((SS){id[sx][sy],sS});
        while (!q.empty()) {
            QS a=q.front();q.pop();
            int u=a.s.u,bS=a.s.S&((1<<icnt)-1),cS=a.s.S>>icnt,dep=a.dep;
            for (int i=0;i<4;i++)
                if (g[u][i]) {
                    int scS=Roll(cS,i);
                    Solve(g[u][i],bS,scS,dep+1);
                }
        }
    }
    
    int main() {
        scanf("%d%d",&m,&n);
        for (int i=1;i<=m;i++) scanf("%s",c[i]+1);
        for (int i=1;i<=m;i++)
            for (int j=1;j<=n;j++) {
                if (c[i][j]!='#') id[i][j]=++icnt;
                if (c[i][j]=='C') sx=i,sy=j;
                if (c[i][j]=='G') tx=i,ty=j;
                if (c[i][j]=='P') sS|=(1<<icnt-1);
            }
        for (int i=1;i<=m;i++)
            for (int j=1;j<=n;j++)
                if (c[i][j]!='#') {
                    if (i>1&&c[i-1][j]!='#') g[id[i][j]][0]=id[i-1][j];
                    if (i<m&&c[i+1][j]!='#') g[id[i][j]][1]=id[i+1][j];
                    if (j>1&&c[i][j-1]!='#') g[id[i][j]][2]=id[i][j-1];
                    if (j<n&&c[i][j+1]!='#') g[id[i][j]][3]=id[i][j+1];
                }
        BFS();
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    [CSS揭秘]扩大可点击区域
    [CSS揭秘]鼠标光标
    [JavaScript语法学习]全面介绍对象
    [JavaScript语法学习]全面介绍函数
    [JavaScript语法学习]全面介绍Array
    [Linux养成计划]Linux简介
    [Redis]Redis安装和使用
    [Python笔记]Python学习笔记三
    Linux_基础_文件权限
    Git_Eclipse:[8]Git分支操作
  • 原文地址:https://www.cnblogs.com/mastervan/p/11117931.html
Copyright © 2011-2022 走看看