比赛的时候没时间做,没办法.昨天早上写了一下.今天交上去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;
}