/*
1151. 魔板[Speical judge]
题目大意:N>10
解题思路:康拓编码
重点注意:
重点1:node下标代表康拓编码,board代表魔板状态
重点2:由于使用了康托编码,空间 大大节省,最多有 8! 种情况
重点3:康拓编码,获得魔板状态的康拓编码
康托编码:
百度百科中对康托展开是这样解释的--{1,2,3,4,...,n}表示1,2,3,...,n的排列,如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321,代表数字 1 2 3 4 5 6,也就是把10进制数与一个排列对应起来,他们间的对应关系可由康托展开来找到。简单的说就是求一个排列数在所有排列中是第几小的。当然,要实现这个功能,途径有很多,比如我们把所有的排列都找出来,然后排个序,二分查找……
德国数学家康托发现其实可以又更简单高效的算法来解决这个问题:例如我们求35412在{1,2,3,4,5}的生成的排列中是第几小的:
第一位是3,第一位比3小的排列数肯定小于35412,比3小的有1,2;共2个数,所以有2*4!;
第二位是5,同理,比5小的有1,2,3,4;因为3已经在前面出现了,所有还有3个比5小的,3*3!;
第三位是4,比4小的有1,2,3;3在前面出现了,还有2个比4小的数,2*2!;
第四位是1,没有比1小的数,所以是0*1!;
最后一位无论是几,比它小的数在前面肯定都出现了,所以有0*0!;
所以,比35412小的排列数共有:2*4!+3*3!+2*2!+0*1!+0*0!=70,35412是第71小的数。
重点4:swap交换函数C语言 #include <string.h>或者#include <algorithm.h>
重点:5:strcmp功能:比较字符串s1和s2。当s1<s2时,返回值<0;当s1=s2时,返回值=0;当s1>s2时,返回值>0 ;属于C语言,因此需要#include <string.h>
重点6:strcmp功能:复制字符串 ;属于C语言,因此需要#include <string.h>
*/
#include <iostream>
#include <cstring> //include <string.h>
#include <queue>
using namespace std;
int factorial[10];
queue<int> q;
struct Node
{
char board[10]; //重点1:node下标代表康拓编码,board代表魔板状态
int step; //step 代表多少步转变
int vis; //vis代表是否存在模版状态
char record[100]; //record代表操作
}node[50000]; //重点2:由于使用了康托编码,空间 大大节省,最多有 8! 种情况
//生成 0到 8的阶乘数组
void init_array()
{
int sum = 1;
factorial[0] = 1;
for (int i = 1; i <= 8; i++)
{
sum *= i;
factorial[i] = sum;
}
}
//重点3:康拓编码,获得魔板状态的康拓编码
int getId(char c[])
{
bool used[10];
int id;
memset(used, false, sizeof(used));
id = 0;
for (int i = 0; i < 8; i ++)
{
for (int j = 1; j < c[i] - '0'; j ++)
if (!used[j])
id += factorial[7 - i];
used[c[i] - '0'] = true;
}
return id;
}
//初始化node数组以及队列q的状态
void init()
{
init_array();
for (int i = 0; i < 50000; i ++)
{
node[i].vis = false;
node[i].step = 0;
node[i].record[0] = '\0';
}
while (!q.empty())
q.pop();
}
void operate1(char temp[], int fa)
{
int idx;
for (int i = 0; i < 4; i ++)
//重点4:swap交换函数C语言 #include <string.h>或者#include <algorithm.h>
swap(temp[i], temp[i + 4]);
idx = getId(temp);
if (!node[idx].vis)
{
strcpy(node[idx].board, temp);
strcpy(node[idx].record, node[fa].record);
node[idx].step = node[fa].step + 1;
node[idx].record[node[idx].step - 1] = 'A';
node[idx].record[node[idx].step] = '\0';
node[idx].vis = true;
q.push(idx);
}
}
void operate2(char temp[], int fa)
{
int idx;
char t1, t2;
t1 = temp[3];
t2 = temp[7];
for (int i = 3; i >= 1; i --)
{
temp[i] = temp[i - 1];
temp[i + 4] = temp[i + 3];
}
temp[0] = t1;
temp[4] = t2;
idx = getId(temp);
if (!node[idx].vis)
{
strcpy(node[idx].board, temp);
strcpy(node[idx].record, node[fa].record);
node[idx].step = node[fa].step + 1;
node[idx].record[node[idx].step - 1] = 'B';
node[idx].record[node[idx].step] = '\0';
node[idx].vis = true;
q.push(idx);
}
}
void operate3(char temp[], int fa)
{
int idx;
char t;
t = temp[1];
temp[1] = temp[5];
temp[5] = temp[6];
temp[6] = temp[2];
temp[2] = t;
idx = getId(temp);
if (!node[idx].vis)
{
strcpy(node[idx].board, temp);
strcpy(node[idx].record, node[fa].record);
node[idx].step = node[fa].step + 1;
node[idx].record[node[idx].step - 1] = 'C';
node[idx].record[node[idx].step] = '\0';
node[idx].vis = true;
q.push(idx);
}
}
int main()
{
init_array();
int N;
char begin[10];
char goal[10];
char hold[10];
int idx;
while(1)
{
cin >> N;
if(N==-1)
break;
init();
//字符初始化
for (int i = 0; i < 4; i ++)
begin[i] = (i + 1) + '0';
for (int i = 4; i < 8; i ++)
begin[11 - i] = (i + 1) + '0';
begin[8] = '\0';
for (int i = 0; i < 8; i ++)
cin >> goal[i];
goal[8] = '\0';
//获得begin字符串的康拓编码
idx = getId(begin);
strcpy(node[idx].board,begin);
node[idx].vis = true;
//队列存储康拓编码
q.push(idx);
while (!q.empty())
{
idx = q.front();
//重:5:strcmp功能:比较字符串s1和s2。当s1<s2时,返回值<0;当s1=s2时,返回值=0;当s1>s2时,返回值>0
//属于C语言,因此需要#include <string.h>
if (strcmp(node[idx].board, goal) == 0)
{
if (node[idx].step <= N)
cout << node[idx].step<<" " << node[idx].record <<endl;
//printf("%d %s\n", node[idx].step, node[idx].record);
else
cout << -1 <<endl;
break;
}
//重点6:strcmp功能:复制字符串
//属于C语言,因此需要#include <string.h>
strcpy(hold, node[idx].board);
operate1(hold, idx);
strcpy(hold, node[idx].board);
operate2(hold, idx);
strcpy(hold, node[idx].board);
operate3(hold, idx);
q.pop();
}
}
return 0;
}
1151. 魔板[Speical judge]
最新推荐文章于 2021-07-15 22:47:21 发布