[状压DP][BFS][哈希]JZOJ 3243 Cube
分析
今日最难,一个旗鼓相当的对手
首先别被总点数迷惑了,总点数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(); }
在日渐沉没的世界里,我发现了你。