poj1077
来源:互联网 发布:php des加密解密 编辑:程序博客网 时间:2024/05/22 16:03
/*基本知识:给每一个全排列一个号:{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进制数与一个排列对应起来。 他们间的对应关系可由康托展开来找到。 如我想知道321是{1,2,3}中第几个大的数可以这样考虑 : 第一位是3,当第一位的数小于3时,那排列数小于321 如 123、 213 ,小于3的数有1、2 。所以有2*2!个。再看小于第二位2的:小于2的数只有一个就是1 ,所以有1*1!=1 所以小于321的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。 2*2!+1*1!是康托展开。 再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个 0*3! 第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2 1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数 0*1! ,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数。首先看几个康托展开的实例(9的全排列):1 2 3 4 5 6 7 8 9——展开为 0。1 2 3 4 5 6 7 9 8——展开为 1。1 2 3 4 5 6 8 7 9——展开为 2。由这些最开始的方法我们可以发现一个规律:从第一个数开始,依次判断判断这些数是当前没有出现过的数的第几个(由0开始),记为a1, a2, ... ,a(n - 1)。不难发现如1 2 3 4 5 6 8 7 9,由1至6都是当前没有出现过的第0个数,而8是7,8,9中的第1个(由0开始),9是7,9中的第1个,7是第0个。故a1 = a2 = ... = a6 = 0,a7 = 1,a8 = 1,a9 = 0。之后排列数(康托展开的值)等于a1 * (n - 1)! + a2 * (n - 2)! + ... + ak * (n - k)! + ... + an * 0!再举几个例子:3 5 7 4 1 2 9 6 8——展开为 98884。5 6 7 8 1 2 3 4 9——展开为 184800。往回转换也很简单,分步取模就可以了,在此就不赘述了。搜索采用单向BFS,足够满足时间需求。*/#include#include#define NUM 362880int queue[NUM],pre[NUM];char dir[NUM];int fac[9]={1, 1, 2, 6, 24, 120, 720, 5040, 40320};//给你一个排列,给我求出是第几个(基本的组合知识)int pack(int *a){int ans=0,i,j,r;char p[10]={0};for(i=0;i<9;i++){for(j=1,r=0;j<=a[i];j++)if(p[j]==0)r++;ans+=(r-1)*fac[8-i];p[a[i]]=1;}return ans;}//给你时第几个排列,求出排列是什么void unpack(int s,int *a){int i,j,r,t;char p[10]={0};for(i=0;i<9;i++){t=s/fac[8-i]+1;s%=fac[8-i];r=0;j=1;while(1){if(p[j]==0)r++;if(r==t)break;j++;}a[i]=j;p[j]=1;}return;}//普及C语言基础,忘了怎么交换,看了书才知道void chang(int *a,int *b){int tmp;tmp=*a;*a=*b;*b=tmp;}int main(){char ch[2];int i,ori,ss[9],flag=0;int cur,temp,p[9],l;for(i=0;i<9;i++)//输入{scanf("%s",ch);if(ch[0]=='x')ss[i]=9;elsess[i]=ch[0]-48;}memset(pre,-1,sizeof(pre));ori=pack(ss);int s=0;int t=0;queue[t++]=0;pre[0]=1;dir[0]=0;while(s!=t)//队列{cur=queue[(s++)%NUM];unpack(cur,p);for(i=0;i<9;i++){if(p[i]==9){temp=i;break;}}//下面四步很经典,分别是如果不是最上边一行就可以往下走,如果不是最下边一行就可以往上走//同理,左右一样//由于输出时倒着输出,所以干好反过来if(temp!=0&&temp!=3&&temp!=6){chang(&p[temp],&p[temp-1]);l=pack(p);if(pre[l]==-1){pre[l]=cur;dir[l]='r';queue[(t++)%NUM]=l;if(l==ori){flag=1;break;}}chang(&p[temp],&p[temp-1]);}if(temp!=2&&temp!=5&&temp!=8){chang(&p[temp],&p[temp+1]);l=pack(p);if(pre[l]==-1){pre[l]=cur;dir[l]='l';queue[(t++)%NUM]=l;if(l==ori){flag=1;break;}}chang(&p[temp],&p[temp+1]);}if(temp!=0&&temp!=1&&temp!=2){chang(&p[temp],&p[temp-3]);l=pack(p);if(pre[l]==-1){pre[l]=cur;dir[l]='d';queue[(t++)%NUM]=l;if(l==ori){flag=1;break;}}chang(&p[temp],&p[temp-3]);}if(temp!=6&&temp!=7&&temp!=8){chang(&p[temp],&p[temp+3]);l=pack(p);if(pre[l]==-1){pre[l]=cur;dir[l]='u';queue[(t++)%NUM]=l;if(l==ori){flag=1;break;}}chang(&p[temp],&p[temp+3]);}}if (flag==0) printf("unsolvable/n"); else { i=ori; while (i!=0) { printf("%c",dir[i]); i=pre[i]; } printf("/n"); } return 0;}一下是转的,留作以后有时间慢慢看//A*C:/Users/Friendy/Desktop/八数码 poj 1077 广搜 A IDA - Andy - 博客园.mht
- poj1077
- poj1077
- POJ1077
- poj1077
- poj1077 Eight
- poj1077小议
- poj1077(A*,IDA*)
- POJ1077 八数码问题
- poj1077 /hdoj 1043 Eight
- poj1077解题报告详解
- 【POJ1077】Eight【IDA*】
- POJ1077——Eight
- POJ1077(8数码问题)
- Eight poj1077 广度优先搜索
- 启发式搜索及应用、POJ1077
- 八数码难题 hdu1043/ poj1077
- poj1077 hdu1043 Eight 八数码问题
- Poj1077/HDU1043(A*搜索)八数码问题
- 初始化成员列表
- 线程间操作无效: 从不是创建控件“...”的线程访问它。
- 唐山大地震观后感
- 菜鸟要开始学习了
- 如何通过外部csv文件编辑产品的价格?
- poj1077
- 与 static 相关的总结
- 如何使用Magento翻译工具?
- 经典SQL语句大全
- 复制粘贴功能失效的解决办法
- 线程终止
- 影评:《唐山大地震》
- 很久不在网上写东西了
- Transact_SQL语句大全