魔板(康托展开去重)

题目链接

题目描述

在魔方风靡全球之后不久,Rubik先生发明了它的简化版——魔板。魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示。任一时刻魔板的状态可用方块的颜色序列表示:从魔板的左上角开始,按顺时针方向依次写下各方块的颜色代号,所得到的数字序列即可表示此时魔板的状态。例如,序列(1,2,3,4,5,6,7,8)表示魔板状态为:
1 2 3 4
8 7 6 5
对于魔板,可施加三种不同的操作,具体操作方法如下:
A: 上下两行互换,如上图可变换为状态87654321
B: 每行同时循环右移一格,如上图可变换为41236785
C: 中间4个方块顺时针旋转一格,如上图可变换为17245368
给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。

Input

每组测试数据包括两行,分别代表魔板的初态与目态。

Output

对每组测试数据输出满足题意的变换步骤。

Sample Input

12345678
17245368
12345678
82754631

Sample Output

C
AC

题意:
给定一个序列怎么通过A,B,C操作变成目态
先bfs把初态“12345678”能通过A,B,C操作能的到的序列先存下来
相当于打表,bfs搜索时其实可以通过map去重,我是用的康托展开去重的
康托展开
最后把目标项转成12345678型的
eg:
初态
4 1 3 6 7 8 2 5
可以对应成
1 2 3 4 5 6 7 8
目态
4 6 7 2 1 3 8 5
对应
1 4 5 7 2 3 6 8
所以就是可以当成12345678---->14572368

#include <bits/stdc++.h>
using namespace std;
string start="12345678";
string end1,ans[50000];
int fac[10],pos[10],vis[50000];

struct node {
	string str,step;
	int can;
};

int KT(string s) {
	int i,j,sum = 0;
	for(i = 0; i<7; i++) {
		int cnt = 0;
		for(j = i+1; j<8; j++)
			if(s[i]>s[j])
				cnt++;
		sum+=cnt*fac[7-i];
	}
	return sum;
}

void fun_A(string &s) {
	for(int i = 0; i<4; i++)
		swap(s[i],s[i+4]);
}

void fun_B(string &s) {
	char t=s[3];
	for(int i=2; i>=0; i--)
		s[i+1]=s[i];
	s[0]=t;
	t=s[7];
	for(int i=6; i>=4; i--)
		s[i+1]=s[i];
	s[4]=t;
}

void fun_C(string &s) {
	char t=s[1];
	s[1]=s[5];
	s[5]=s[6];
	s[6]=s[2];
	s[2]=t;
}

void bfs() {
	node now,next;
	queue<node> que;
	now.step = "";
	now.str = start;
	now.can = KT(start);
	vis[now.can] = 1;
	ans[now.can] = "";
	que.push(now);
	while(!que.empty()) {
		now = que.front();
		string t;
		int k;
		t = now.str;
		fun_A(t);
		k = KT(t);
		if(!vis[k]) {
			vis[k] = 1;
			next = now;
			next.step+='A';
			ans[k] = next.step;
			next.str = t;
			next.can = k;
			que.push(next);
		}
		t = now.str;
		fun_B(t);
		k = KT(t);
		if(!vis[k]) {
			vis[k] = 1;
			next = now;
			next.step+='B';
			ans[k] = next.step;
			next.str = t;
			next.can = k;
			que.push(next);
		}
		t = now.str;
		fun_C(t);
		k = KT(t);
		if(!vis[k]) {
			vis[k] = 1;
			next = now;
			next.step+='C';
			ans[k] = next.step;
			next.str = t;
			next.can = k;
			que.push(next);
		}
		que.pop();
	}
}

int main() {
	fac[0] = 1;
	for(int i = 1; i<10; i++)
		fac[i] = fac[i-1]*i;
	memset(vis,0,sizeof(vis));
	bfs();
	while(cin>>start>>end1) {
		swap(start[4],start[7]);
		swap(start[6],start[5]);
		swap(end1[4],end1[7]);
		swap(end1[6],end1[5]);
		for(int i=0; i<8; i++)
			pos[start[i]-'0'] = i+1;
		for(int i=0; i<8; i++)
			end1[i] = pos[end1[i]-'0'];
		int k;
//		cout<<KT("12345687")<<endl;
		k = KT(end1);
		cout << ans[k] << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值