您的位置:首页 > 其它

HDU_1430——魔板,预处理,康托展开,置换,string类的+操作

2013-07-25 10:59 453 查看
[align=left]Problem Description[/align]
在魔方风靡全球之后不久,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
给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。

[align=left]Input[/align]
每组测试数据包括两行,分别代表魔板的初态与目态。

[align=left]Output[/align]
对每组测试数据输出满足题意的变换步骤。

[align=left]Sample Input[/align]

12345678
17245368
12345678
82754631

[align=left]Sample Output[/align]

C
AC

#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;

const int MAXN = 40321;        //由于此题数字1~8,康托展开的所有情况为8!,共40320种
const int fac[8] = {1,1,2,6,24,120,720,5040};    //康托展开中用到的0~7的阶乘
string ans[MAXN];                //存储各状态的变化步骤,预处理完成

struct node
{
int a[8];
int n;
}u,v;

void A(node &t)    //A操作
{
swap(t.a[0],t.a[7]);
swap(t.a[1],t.a[6]);
swap(t.a[2],t.a[5]);
swap(t.a[3],t.a[4]);
}
void B(node &t)    //B操作

{
swap(t.a[3],t.a[2]);
swap(t.a[2],t.a[1]);
swap(t.a[1],t.a[0]);
swap(t.a[4],t.a[5]);
swap(t.a[5],t.a[6]);
swap(t.a[6],t.a[7]);
}
void C(node &t)    //C操作
{
swap(t.a[1],t.a[6]);
swap(t.a[6],t.a[5]);
swap(t.a[5],t.a[2]);
}

int contor(node &t)        //康托展开
{
int tmp, num = 0;
for(int i=0; i<8; i++)
{
tmp = 0;
for(int j=i+1; j<8; j++)
{
if(t.a[j] < t.a[i])
{
tmp++;
}
}
num += tmp*fac[7-i];
}
return num;
}

void Init(void)
{
void (*ptr[3])(node&);                        //定义函数指针
ptr[0] = A; ptr[1] = B; ptr[2] = C;        //指向对应函数方便处理

int mark[MAXN] = {0};                        //设置标记
mark[0] = 1;

for(int i=0; i<8; i++)                        //由初始状态12345678开始
{
u.a[i] = i+1;
}
u.n = contor(u);

queue<node>que;
que.push(u);
while(!que.empty())
{
u = que.front();
que.pop();

for(int i=0; i<3; i++)                //三种变换
{
v = u;
(*ptr[i])(v);
v.n = contor(v);                    //对副本执行操作并康托展开
if(mark[v.n] == 0)                //重复
{
char ch = 'A' + i;
ans[v.n] = ans[u.n] + ch;    //记录步骤

mark[v.n] = 1;                    //标记
que.push(v);
}
}
}
}

int main()
{
Init();
char a[10],b[10];
while(~scanf("%s%s",a,b))
{
int n[10];
for(int i=0; i<8; i++)            //把初态置换成12345678
{
n[a[i] - '0'] = i+1;
}

for(int i=0; i<8; i++)            //把目标状态相对于初态置换
{
u.a[i] = n[b[i] - '0'];
}

cout<<ans[contor(u)]<<endl;    //输出由12345678到目标态的步骤
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: