hdu1430 魔板(康拓展开 bfs预处理)

魔板

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4050    Accepted Submission(s): 951


Problem Description
在魔方风靡全球之后不久,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


题目传送门

思路:是先了解了康托展开再做这道题,想当于是用康拓展开给每一种状态弄一个独立的标号,可以快速找到某一种状态,所以就是先用12345678为初始状态,然后记录每一种状态的contor值,这里我用了把函数写在结构体里的方法,方便简洁(学习了网上一位大佬),然后比较难想就是,每一次输入的初态和末态并不都是12345678,如何将输入和bfs中的状态对应起来呢?

我们就需要置换一下。

置换: 原始态为“12345678”  例如 初态是 “45781236”  目态是 ”78451326“  

目态的第一位‘7’ 在初态中是第三位, 而原始态的第三位是‘3’,故目态的第一位应该转换为‘3’,(就是将输入的值和12345678一一对应)就这样一次转换  最后目态转换为  34125768, 最后找出34125768对应的康拓值,输出就好了。 

而字典序的话,每一次bfs都是按照ABC这样的顺序的,所以每种状态的步骤必然是最小字典序。

具体看代码。

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<bitset>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define CLR(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
using namespace std;
typedef long long ll;
const int N=40320+10;
int fact[9]= {1,1,2,6,24,120,720,5040,40320};
struct info{
	int arr[8];
	int val;//计算出来的康托展开的序号 
	string step;
	void contor(){//把康托展开写在结构体里面 
		val=0;
		for(int i=0;i<8;i++){
			int t=0;
			for(int j=i+1;j<8;j++){
				if(arr[j]<arr[i])t++;
			}
			val+=t*fact[8-i-1];
		}
		val++;
	}
	void change_a(){
		reverse(arr,arr+8);
		step+='A';
	} 
	void change_b(){
        int temp=arr[3];
        for (int i=3; i>0; --i)
            arr[i]=arr[i-1];
        arr[0]=temp;
        temp=arr[4];
        for (int i=4; i<7; ++i)
            arr[i]=arr[i+1];
        arr[7]=temp;
        step+="B";
    }
	void change_c(){
		int temp=arr[1];
		arr[1]=arr[6];
		arr[6]=arr[5];
		arr[5]=arr[2];
		arr[2]=temp;
		step+='C';
	}
};
int vis[N];
string ans[N];//记录每一种状态的操作 
int re[8];
info s,t;
void bfs(){
	queue<info>q;
	vis[s.val]=1;
	q.push(s);
	info now,v;
	while(!q.empty()){
		now=q.front();
		q.pop();
		v=now;
		int len=v.step.length();
		if(len<1||v.step[len-1]!='A'){//去掉AA这样的情况 
			v.change_a();
			v.contor();
			if(!vis[v.val]){
				vis[v.val]=1;
				ans[v.val]=v.step;
				q.push(v);
			}
		}
		v=now;
		if(len<3||v.step[len-1]!='B'||v.step[len-2]!='B'||v.step[len-3]!='B'){//去掉BBBB这样的情况 
			v.change_b();
			v.contor();
			if(!vis[v.val]){
				vis[v.val]=1;
				ans[v.val]=v.step;
				q.push(v);
			}
		}
		v=now;
		if(len<3||v.step[len-1]!='C'||v.step[len-2]!='C'||v.step[len-3]!='C'){//去掉CCCC这样的情况 
			v.change_c();
			v.contor();
			if(!vis[v.val]){
				vis[v.val]=1;
				ans[v.val]=v.step;
				q.push(v);
			}
		}
	}
}
int main(){
	for(int i=0;i<8;i++){
		s.arr[i]=i+1;
	}//初始化  12345678 
	s.contor();
	bfs();
	char ss[10];
	while(scanf("%s",ss)!=EOF){
		for(int i=0;i<8;i++){
		re[ss[i]-'0']=i+1;
		}//将输入的初始状态的字符 和12345678(bfs中的初始状态)一一对应  
		scanf("%s",ss);
		for(int i=0;i<8;i++){
			t.arr[i]=re[ss[i]-'0'];//找到当前的目标状态在bfs中对应的值 
		}
		t.contor();
		printf("%s\n",ans[t.val].c_str());
	}
}


 

转载于:https://www.cnblogs.com/mountaink/p/9536728.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值