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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 香港海洋公园4日游 香港海洋公园一日游 全球无限战场 沐日海洋 湛江海洋大学是几本 大连海洋大学是几本 上海海洋大学是211吗 中国海洋大学是985吗 青岛海洋大学是211还是985 海洋芭莎是什么品牌 广东海洋大学是一本吗 厦门海洋学院是几本 大连海洋大学是一本吗 上海海洋大学是几本 浙江海洋大学是一本还是二本 中国海洋大学是211吗 你是我眼中的山川和海洋歌曲 中国海洋大学是几本 你是我眼中的山川和海洋txt 女的梦见海洋是什么预兆 知识是什么的海洋 广州海洋大学是几本 香港海洋公园门票价格是多少 海洋大学是几本 中国海洋大学是985还是211 香港海洋公园的门票是多少 广东海洋大学是一本还是二本 海洋主义是正规牌子吗 你是我眼中的山川和海洋免费 我国的海洋国土面积是多少 你是我眼中的山川与海洋 青岛海洋大学是几本 上海海洋大学是一本吗 浙江海洋学院是几本 你是我眼中的山川和海洋结局 你是我眼中的山川和海洋 广东海洋大学是211吗 上海海洋大学是基本 江苏海洋大学是一本吗 海洋公园门票是多少 北极熊是海洋动物吗 世界海洋日是几月几日