魔方 大模拟

魔方(cube.cpp)

题目描述:

给出一个二阶魔方,保证 N 步以内能够还原。“还原”被定义为每个面均为纯色。

请给出,操作编号字典序最小,且不存在同类操作相邻,的还原方案。



输入格式:

第一行一个正整数N,表示最多步数。

接下来24个整数,按上图的顺序依次给出Ci,Ci∈{1,2,3,4,5,6}。

输出格式:

一行,t个用空格隔开的正整数,表示复原的最小字典序操作序列,要求0 < t ⩽ N。

最后一个数后无空格,数据保证输入魔方是打乱的。

注:(1,2,3) 虽然长度长于(2,3),但字典序更小。

样例读入:

2

1 1 1 1

4 4 2 2

6 6 3 3

3 3 6 6

5 5 5 5

4 4 2 2

样例输出:

2

样例解释:

因为不能类别相同的操作相邻,所以只有2种操作方式可以在两步内复原此时的魔方:(2),(17),故字典序最小的为(2)。

数据范围:

对于 20% 的数据,保证 N = 1

对于 40% 的数据,保证 N ⩽ 3

对于另20%的数据,保证 N ⩽ 6,且保证答案只用到前6种操作

对于100% 的数据,保证 N ⩽ 7

题解:一开始看到数据范围还以为是状态压缩,将魔方的每个状态表示出来,结果发现不对。其实就是大模拟,如果每次枚举18个操作,时间复杂度是O(n^18),显然会超时,只能拿60分。其实不难发现,不管怎样,答案中的操作只能在1~9之间,比如底面顺时针90度=顶面顺时针270度,底面180度=顶面180度,底面270度=顶面90度。所以只用枚举一面即可,于是就AC了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
int tag[20];
int work[30],flag=0,opt[30];

int fa=0;
unsigned long long get_hash()
{
	fa++;
	unsigned long long Hash=0;
	for(int i=1;i<=8;i++) Hash=Hash*11+work[i];
	return Hash;
}
void init()
{
	for(int i=1;i<=3;i++) tag[i]=tag[18-i+1]=1;
	for(int i=4;i<=6;i++) tag[i]=2;
	for(int i=7;i<=9;i++) tag[i]=3;
	for(int i=10;i<=12;i++) tag[i]=2;
	for(int i=13;i<=15;i++) tag[i]=3;
}
void change_(int id)
{
	int a,b,c;
	switch(id)
	{
		case 1:{//ding
			a=work[5];b=work[6];c=work[1];
			work[5]=work[13];work[6]=work[14];
			work[13]=work[24];work[14]=work[23];
			work[23]=work[10];work[24]=work[9];
			work[9]=a;work[10]=b;
			work[1]=work[3];work[3]=work[4];work[4]=work[2];work[2]=c;
			break;
		}
		case 2:{
			swap(work[5],work[24]);swap(work[6],work[23]);
			swap(work[13],work[9]);swap(work[14],work[10]);
			swap(work[1],work[4]);swap(work[2],work[3]);
			break;
		}
		case 3:{
			a=work[5];b=work[6];c=work[1];
			work[5]=work[9];work[6]=work[10];
			work[9]=work[24];work[10]=work[23];
			work[23]=work[14];work[24]=work[13];
			work[13]=a;work[14]=b;
			work[1]=work[2];work[2]=work[4];work[4]=work[3];work[3]=c;
			break;
		}
		case 4:{
			a=work[1];b=work[3];c=work[9];
			work[1]=work[21];work[3]=work[23];
			work[21]=work[17];work[23]=work[19];
			work[17]=work[5];work[19]=work[7];
			work[5]=a;work[7]=b;
			work[9]=work[11];work[11]=work[12];work[12]=work[10];work[10]=c;
			break;
		}
		case 5:{
			swap(work[1],work[17]);swap(work[3],work[19]);
			swap(work[5],work[21]);swap(work[7],work[23]);
			swap(work[9],work[12]);swap(work[10],work[11]);
			break;
		}
		case 6:{
			a=work[1];b=work[3];c=work[9];
			work[1]=work[5];work[3]=work[7];
			work[5]=work[17];work[7]=work[19];
			work[17]=work[21];work[19]=work[23];
			work[21]=a;work[23]=b;
			work[9]=work[10];work[10]=work[12];work[12]=work[11];work[11]=c;
			break;
		}
		case 7:{
			a=work[3];b=work[4];c=work[5];
			work[3]=work[12];work[4]=work[10];
			work[10]=work[17];work[12]=work[18];
			work[17]=work[15];work[18]=work[13];
			work[13]=a;work[15]=b;
			work[5]=work[7];work[7]=work[8];work[8]=work[6];work[6]=c;
			break;
		}
		case 8:{
			swap(work[3],work[18]);swap(work[4],work[17]);
			swap(work[13],work[12]);swap(work[15],work[10]);
			swap(work[5],work[8]);swap(work[6],work[7]);
			break;
		}
		case 9:{
			a=work[3];b=work[4];c=work[5];
			work[3]=work[13];work[4]=work[15];
			work[13]=work[18];work[15]=work[17];
			work[17]=work[10];work[18]=work[12];
			work[10]=b;work[12]=a;
			work[5]=work[6];work[6]=work[8];work[8]=work[7];work[7]=c;
			break;
		}
	}
}
void dfs(int dep,int last)
{
	bool cct=0;
	for(int i=0;i<6;i++)
	{
		int tmp=work[(i*4)+1];
		for(int j=1;j<=4;j++)
			if(work[(i*4)+j]!=tmp)
			{
				cct=1;break;
			}
		if(cct) break;
	}
	if(!cct)
	{
		flag=1;dep--;
		for(int i=1;i<dep;i++) printf("%d ",opt[i]);printf("%d\n",opt[dep]);
		return ;
	 }
	if(dep==n+1) return ;
	int ccr[50];
	for(int i=0;i<6;i++)
	    for(int j=1;j<=4;j++)
	       ccr[(i*4)+j]=work[(i*4)+j];
	for(int i=0;i<=2;i++)
	{
		if(last==i) continue;
		for(int j=(i*3+1);j<=(i+1)*3;j++)
		{
			if(flag) return ;
			change_(j);opt[dep]=j;
			dfs(dep+1,i);
			if(flag) return ;
			for(int k=0;k<6;k++)
				for(int fe=1;fe<=4;fe++)
				   work[(k*4)+fe]=ccr[(k*4)+fe];
		}
	}
}
int main()
{
//	freopen("cube.in","r",stdin);
//	freopen("cube.out","w",stdout);
	init();
	int x;
	scanf("%d",&n);
	for(int i=0;i<6;i++)
		for(int j=1;j<=4;j++)
			scanf("%d",&x),work[(i*4)+j]=x;
	dfs(1,-1);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值