比赛的时候没时间做,没办法.昨天早上写了一下.今天交上去1A ,
最喜欢这样的搜索了,没难度.
思路:魔方的旋转方法总共有12种,
只考虑前面的四个正方形,上面向左旋转,跟下面向右旋转是一个效果,方法数可以除2..
向右旋转一次等于向左旋转两次,可以一起处理,方法数再减半.三种情况.代码很短.
只有两种颜色,很多重复状态.用map当hash页不会超时.100ms水过.比标程代码短时间少..
分享代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> #include <stack> #include <map> #include <string> #define LL long long #define DB double #define SF scanf #define PF printf #define N 1<<24 #define bug cout<<"bug"<<endl; using namespace std; map<int,int> mp; struct nod{ int a[25]; int dis; }; int cc[20][15]={ {0,1,4,5,20,21,12,13}, {8,11,10,9}, {18,16,2,0,9,10,21,23}, {13,12,14,15}, {4,6,17,16,15,13,9,8}, {0,1,3,2}, }; void turn(nod &t,int c) { c<<=1; int tmp = t.a[cc[c][7]]; for(int i=7;i>0;i--) { t.a[cc[c][i]]=t.a[cc[c][i-1]]; } t.a[cc[c][0]] = tmp; tmp = t.a[cc[c][7]]; for(int i=7;i>0;i--) { t.a[cc[c][i]]=t.a[cc[c][i-1]]; } t.a[cc[c][0]] = tmp; tmp = t.a[cc[c|1][3]]; for(int i=3;i>0;i--) { t.a[cc[c|1][i]]=t.a[cc[c|1][i-1]]; } t.a[cc[c|1][0]] = tmp; } nod in; queue<nod> que; int gethas(nod &t) { int ret = 0; for(int i=0;i<24;i++) { ret = t.a[i]+(ret<<1); }return ret; } bool ok(nod &t) { for(int i=0;i<24;i+=4) { for(int j=1;j<4;j++) if(t.a[i]!=t.a[i+j]) return false; }return true; } int solve() { int con = 0; for(int i=0;i<24;i++) if(in.a[i]) con++; if(con%4) return -1; in.dis = 0; while(!que.empty()) que.pop(); que.push(in); mp.clear(); mp[gethas(in)] = 1; nod e,t; if(ok(in)) return t.dis; while(!que.empty()) { e = que.front();que.pop(); for(int i=0;i<3;i++) { t = e;t.dis++; turn(t,i); if(mp.find(gethas(t))==mp.end()) { mp[gethas(t)] = 1;//bug if(ok(t)) return t.dis; que.push(t); } turn(t,i); turn(t,i); if(mp.find(gethas(t))==mp.end()) { mp[gethas(t)] = 1;//bug if(ok(t)) return t.dis; que.push(t); } } }return -1; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int cas;SF("%d",&cas); while(cas--) { for(int i=0;i<24;i++) SF("%d",&in.a[i]); int k = solve(); if(k==-1) printf("IMPOSSIBLE!\n"); else printf("%d\n",k); } return 0; }