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

康拓展开原理:

来自: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
   
   
   
   
12345678 17245368 12345678 82754631
 

Sample Output
   
   
   
   
C AC
 

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;
}



你可能感兴趣的:(C语言,bfs)