1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 x
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8 9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12 13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x r-> d-> r->
2 3 4 1 5 x 7 6 8Sample Output
ullddrurdllurdruldr
AC:
#include
#include
#include
using namespace std;
struct node1{
char way;//路径
int pre;//父节点
};
node1 Node[370000];//节点
struct node2{
int aa[10];
int n,cnt;//n为 9在aa中的位置,cnt为aa在9的字典序全排列的中的位置
};
int end1[9];//终态
int fac[10];
int dx[]={1, -1, 0, 0};
int dy[]={0, 0, 1, -1};
// 下 上 右 左
char paths[]={'u','d','l','r'};//记录路径时记录相反的方向
void Get_fac()//计算0-9的阶乘
{
fac[0]=1;
for(int i=1;i<=9;i++)
fac[i]=fac[i-1]*i;
}
int kangtuo(int aa[])//康托展开
{
int i,j,ans=0,k;
for(i=0;i<9;i++)
{
k=0;
for(j=i+1;j<9;j++)
if(aa[i]>aa[j])
k++;
ans+=k*fac[8-i];
}
ans++;
return ans;
}
void bfs()
{
queueQ;
node2 p,q;
for(int i=0;i<9;i++)
p.aa[i]=end1[i];
p.n=8,p.cnt=1;
Node[p.cnt].pre=1;//终态的父节点为1,即终态为根节点
Q.push(p);
while(!Q.empty())
{
p=Q.front();
Q.pop();
for(int i=0;i<4;i++)//9与其所在位置的下上右左分别交换位置
{
q=p;
int tx,ty;
tx=p.n/3+dx[i];//9的下一个位置的横坐标
ty=p.n%3+dy[i];//9的下一个位置的纵坐标
if(tx>=0 && tx<3 && ty>=0 && ty<3)//未出界
{
int tnum;
q.n=tx*3+ty;//计算9的在数组中下一个位置
tnum=q.aa[p.n];
q.aa[p.n]=q.aa[q.n];
q.aa[q.n]=tnum;
q.cnt=kangtuo(q.aa);//康托展开计算当前态在全排列中的位置
if(Node[q.cnt].pre==-1)//为-1时表示这个点没有访问过,那么放入队列
{
Node[q.cnt].pre=p.cnt;//当前节点的父节点就是上一个节点
Node[q.cnt].way=paths[i];//记录路径
Q.push(q);
}
}
}
}
}
int main()
{
for(int i=0;i<9;i++)
end1[i]=i+1;
for(int i=0;i<370000;i++)//初始化,每一种情况都未被访问过
Node[i].pre=-1;
Get_fac();
bfs();//预处理,以终态为根节点建立一树
char c[20];
while(gets(c)>0)
{
int start1[10];
int k=0;
for(int i=0;i='0' && c[i]<='9')
{
start1[k++]=c[i]-'0';
}
}
//for(int i=0;i<9;i++);
/*加上这一句,你会发现不一样的东西(在我电脑上样例输出结果不一样,不
知道是不是我的编译器的问题 QAQ ),但两种情况都能AC*/
int cnt=kangtuo(start1);//算出初态的康托值
//printf("%d\n",cnt);
if(Node[cnt].pre==-1)//终态不能变成初态
{
printf("unsolvable\n");
continue;
}
while(cnt!=1)//从现态往回搜,一直到根,结束
{
printf("%c",Node[cnt].way);
cnt=Node[cnt].pre;
}
printf("\n");
}
return 0;
}
参考代码:点击打开链接
康托展开:点击打开链接
//上面的问题是数组开的太小了,但是侥幸水过了,学长看了下把数组改大就不会出错了,但是还是不知道为什么加个for循环结果就正确了
#include
#include
#include
using namespace std;
struct node1{
char way;//路径
int pre;//父节点
};
struct node2{
int aa[10];
int n,cnt;//
};//节点
node1 Node[370000];
int end1[9];
int fac[10];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
char paths[]={'u','d','l','r'};
void Get_fac()//计算0-9的阶乘
{
fac[0]=1;
for(int i=1;i<=9;i++)
fac[i]=fac[i-1]*i;
}
int kangtuo(int aa[])//康托展开
{
int j,ans=0,k;
for(int i=0;i<9;i++)
{
k=0;
for(j=i+1;j<9;j++)
if(aa[i]>aa[j])
k++;
ans+=k*fac[8-i];
}
ans++;
return ans;
}
void bfs()
{
queueQ;
node2 p,q;
for(int i=0;i<9;i++)
p.aa[i]=end1[i];
p.n=8,p.cnt=1;
Node[p.cnt].pre=1;
Q.push(p);
while(!Q.empty())
{
p=Q.front();
Q.pop();
for(int i=0;i<4;i++)
{
q=p;
int tx,ty;
tx=p.n/3+dx[i];
ty=p.n%3+dy[i];
if(tx>=0 && tx<3 && ty>=0 && ty<3)
{
int tnum;
q.n=tx*3+ty;
tnum=q.aa[p.n];
q.aa[p.n]=q.aa[q.n];
q.aa[q.n]=tnum;
q.cnt=kangtuo(q.aa);
if(Node[q.cnt].pre==-1)
{
Node[q.cnt].pre=p.cnt;
Node[q.cnt].way=paths[i];
//printf("%c ",paths[i]);
Q.push(q);
}
}
}
}
}
int main()
{
for(int i=0;i<9;i++)
end1[i]=i+1;
for(int i=0;i<370000;i++)
Node[i].pre=-1;
Get_fac();
bfs();
char c[30];
//char c[20]; //开20太勉强了,反正内存不要钱,多开一点,避免出现不可预期的错误。
while(gets(c)>0)
{
int start1[10];
int k=0,i;
for( i=0;i<40;i++)
printf("C %c: %d\n",c[i],&c[i]);
printf("i %d\n",&i);
printf("start1[0] %d\nstart1[9] %d\n",&start1[0],&start1[9]);
printf("k %d\n",&k);
for(int i=0;i='0' && c[i]<='9')
{
start1[k++]=c[i]-'0';
}
}
//样例是输入 2 3 4 1 5 x 7 6 8,输出 ullddrurdllurdruldr
//样例一共9个字符,且字符之间是两个空格,不是一个哦。
for(int i=0;i<9;i++);//加这个废的for循环 结果ullddrurdllurrdlurd 正确
//for(int kkk=0;kkk<9;kkk++);//把i替换成前面代码没有用过的变量kkk, 结果还是 ullddrurdllurrdlurd 正确
//不加这个for循环 结果lurullddrurdllurdr 这个结果是错误的
int cnt=kangtuo(start1);
if(Node[cnt].pre==-1)
{
printf("unsolvable\n");
continue;
}
while(cnt!=1)
{
printf("%c",Node[cnt].way);
cnt=Node[cnt].pre;
}
printf("\n");
}
return 0;
}