hdu 1430 魔板(bfs+预处理+康托展开)

来源:互联网 发布:率土之滨魅族端口 编辑:程序博客网 时间:2024/05/18 17:43

康拓展开原理:

来自:http://blog.csdn.net/zhongkeli/article/details/6966805 

康托展开的公式是 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,ai为当前未出现的元素中是排在第几个(从0开始)。
  这个公式可能看着让人头大,最好举个例子来说明一下。例如,有一个数组 s = ["A", "B", "C", "D"],它的一个排列 s1 = ["D", "B", "A", "C"],现在要把 s1 映射成 X。n 指的是数组的长度,也就是4,所以
X(s1) = a4*3! + a3*2! + a2*1! + a1*0!
关键问题是 a4、a3、a2 和 a1 等于啥?
a4 = "D" 这个元素在子数组 ["D", "B", "A", "C"] 中是第几大的元素。"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,"D"是第3大的元素,所以 a4 = 3。
a3 = "B" 这个元素在子数组 ["B", "A", "C"] 中是第几大的元素。"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,所以 a3 = 1。
a2 = "A" 这个元素在子数组 ["A", "C"] 中是第几大的元素。"A"是第0大的元素,"C"是第1大的元素,所以 a2 = 0。
a1 = "C" 这个元素在子数组 ["C"] 中是第几大的元素。"C" 是第0大的元素,所以 a1 = 0。(因为子数组只有1个元素,所以a1总是为0)
所以,X(s1) = 3*3! + 1*2! + 0*1! + 0*0! = 20

具体实现如下:
A B C | 0
A C B | 1
B A C | 2
B C A | 3
C A B | 4
C B A | 5

首先我们采用康托展开就是可以将任何一个排列转换成唯一的数字。因为我们要标记这个序列是否访问过的话,是不可以吧一个字符串放进数组的,必须运用康托展开将这个字符串序列转换成唯一的数字,标记才有意义。


其次就是预处理。

根本就是将所有的始态的换成统一的形式,将对应位置的数字分别对应为12345678,举一个例子,如下:

始态13542687 目标态12345678 


转化方式为

 for (int i=0; i<8; i++)//得到对应关系        {            nn[ch[i]-'0']=i+1;        }
得到之后,按照对应关系将原来的目标态转化新的目标态

 for (int i=0;i<8;i++)//将目标态按照转换关系变成过程态的对应的目标态        {            str[i]=nn[str[i]-'0']+'0';        }

转换完成之后,按照这个过程态对目标态进行搜索。这个初始态的所有变换情况已经预处理完成。

详见题目。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1430

魔板

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


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
12345678172453681234567882754631
 

Sample Output
CAC
 

Author
LL
 

Source
ACM暑期集训队练习赛(三)
 

Recommend
linle   |   We have carefully selected several similar problems for you:  1429 1426 1427 1401 1043 


 详见代码。
#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <queue>using namespace std;struct node{    string st;//表示当前的状态    string step;//变化的过程} s,ss;int num[15];//阶乘int vis[400000];string Count[400000];void fac(){    num[0]=1;    num[1]=1;    for (int i=1; i<10; i++)        num[i]=num[i-1]*i;}int Cantor(string &ch){    int ans=0;    for (int i=0; i<8; i++)    {        int t=0;        for (int j=i+1; j<8; j++)        {            if (ch[i]>ch[j])                t++;        }        ans+=t*num[8-i-1];    }    return ans;}void fun_A(string &ch){    for (int i=0; i<4; i++)        swap(ch[i],ch[8-i-1]);}void fun_B(string &ch){    int t=ch[3];    //ch[0]=ch[3];    for (int i=3; i>=1; i--)        ch[i]=ch[i-1];    ch[0]=t;    int tt=ch[4];    for (int i=4; i<=6; i++)        ch[i]=ch[i+1];    ch[7]=tt;}void fun_C(string &ch){    int t=ch[6];    ch[6]=ch[5];    ch[5]=ch[2];    ch[2]=ch[1];    //ch[1]=ch[6];    ch[1]=t;}void bfs(){    queue<node>q,qq;    s.st="12345678";    s.step="";    //vis[6909000]= {0};    memset(vis,0,sizeof(vis));    q.push(s);    vis[Cantor(s.st)]=1;    while (!q.empty())    {        s=q.front();        q.pop();        //int cnt= Cantor(s.st);        //count[cnt]=s.st;        ss=s;        //cout<<s.st<<" "<<s.step<<endl;        fun_A(ss.st);        //cout<<ss.st<<endl;        int cnt= Cantor(ss.st);        if (!vis[cnt])        {            ss.step+="A";            Count[cnt]=ss.step;            q.push(ss);            vis[cnt]=1;        }        ss=s;        fun_B(ss.st);        //cout<<ss.st<<endl;        cnt= Cantor(ss.st);        if (!vis[cnt])        {            ss.step+="B";            Count[cnt]=ss.step;            q.push(ss);            vis[cnt]=1;        }        ss=s;        fun_C(ss.st);        //cout<<ss.st<<endl;        cnt= Cantor(ss.st);        if (!vis[cnt])        {            ss.step+="C";            Count[cnt]=ss.step;            q.push(ss);            vis[cnt]=1;        }    }    //printf ("\n");}int main(){    string ch;    string str;    fac();    bfs();    while (cin>>ch)    {        //cout<<ch<<endl;        int nn[15];        for (int i=0; i<8; i++)//得到对应关系        {            nn[ch[i]-'0']=i+1;        }        cin>>str;        for (int i=0;i<8;i++)//将目标态按照转换关系变成过程态的对应的目标态        {            str[i]=nn[str[i]-'0']+'0';        }        //cout<<str<<endl;        int ann=Cantor(str);        cout<<Count[ann]<<endl;    }    return 0;}



1 0
原创粉丝点击