康拓展开原理:
来自: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
12345678 17245368 12345678 82754631
C AC
#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; }