外星人计数

来源:互联网 发布:apache windows 编辑:程序博客网 时间:2024/05/02 01:53
// 外星人计数法.cpp : 定义控制台应用程序的入口点。//DJ.W  2013.3.30/*问题描述:下面是外星人计数和人类计数的对应外星人计数人类计数11122213123413252136231731283219123410.......要求输入人类计数,计算并输出对应外星人计数表示例:输入:234   输出:153426*//*思路:按照上面说给出的规律: 外星人计数按照数字个数由少到多,排列值由小到大(按照人类计数)的顺序依次对应于人类计数那么对于一个人类计数 n 可化为 n = 1!+2!+3!+...i!+k            (0 < k<=(i+1)! )这样我们可以知道n对应的外星人计数是由i+1位数(1..i+1)组成的,它对应的具体排列就是i+1位数所有排列中,由小到大的第k个数。如 : 10 = 1!+2!+3!+1   那么10的外星人计数就是(1 2 3 4)四位数所有排列中,第一小即最小的排列1234又如: 7 = 1!+2!+4那么7的对应外星人计数就是(1 2 3)三位数由小到大排列的第四个数 即231 这是解决问题的第一步第二步:此时此题就化为了如果在i个数的排列中,得到由小到大的第k个数(0<k<=(i!))。如i=4时的排列: 1234 1243 1324 1342 1423 1432 2134......我们可以观察得出,首位的1在经过了(i-1)!=3!=6次之后,才变为2,而第二位的2经过了(i-2)!=2次之后才变为3依次类推:自左向右第j位在经过(i-j)!之后才变为下一个数,并且只要它前面的j-1个数没变,那么它的下一个数必定是比它大的可用数 如在 2134 2143 2314 2341 2413 2431 中,当左边第一位2没变时,第二位是递增的,当第一第二位没变时,第三位是递增的。。。解释这些可能让问题更糊涂,其实上面主要就是想证明它的递归特性。下面举一个数字的完整转换,比如对于输入234234 = 1!+2!+3!+4!+5!+81即234的表示是(1 2 3 4 5 6)六个数由小到大的第81个排列由于81<5!=120 因此后五位变化还没有到一个周期,所以首位为1 此时还剩后五位2 3 4 5 681- 4! * 3= 9  后4位变化了三个周期,因此它们的前一位(第二位)递增了3次,即在2 3 4 5 6中的5 此时还剩后四位2 3 4 69- 3!= 3  后三位变化了一个周期,因此它们的前一位(第三位)递增了1次,即为2 3 4 6中的3 还剩后三位2 4 63- 2!= 1  后两位递增了一个周期,那么第四位递增一次,为2 4 6中的4还剩2 6此时只剩下1,即代表是2 6 两个数表示中最小的, 即26注意:如果是235 即最后是4-2! 不能算成4-2!*2=0 0意味着第0小的排列 无意义,而4-2!=2意味着最后两个数最大的排列综上 234 的外星表示为 153426*/#include "stdafx.h"#include <iostream>#include<windows.h>using namespace std;#include<vector>int _tmain(int argc, _TCHAR* argv[]){//获取输入cout<<"输入人类数字: "<<endl;int n;cin>>n;while(n<0){cout<<"n < 0无法转换,请重新输入: "<<endl;cin>>n;}//第二步,得到k和i 使得n = 1! + 2! + 3! + ... + i! + kint acc = 0;//1! + 2! + ... + i!int i = 0;int ifact = 1;//i!int iplusfact;//(i+1)!while(true){iplusfact = (i+1)*ifact;if (n - acc <= iplusfact)break;acc += iplusfact;i++;ifact = iplusfact;}int k = n-acc;//第二步 得到i!个排列中由小到大第k个排列int nCircle;//当前递增了多少个周期vector<int> vNumCanUse;//当前可用的数for (int j=1; j<=i+1; j++)vNumCanUse.push_back(j);cout<<"转换为外星表示法为:"<<endl;while (i > 1){//当前计算后面i+1位中的最高位上的数字nCircle = (k-1)/ifact;//此处用k-1是为了保证 4 = 2! + 2 而不是 4 = 2!*2cout<<vNumCanUse.at(nCircle);//取得当前可用的第nCircle小的数 作为当前位的数vNumCanUse.erase(vNumCanUse.begin()+nCircle); //移除该数//转到后面i位k = (k-1)%ifact+1;ifact = ifact/i;i--;}//对于最后两位数 即i==1时  可直接判断if (k == 1){cout<<vNumCanUse.at(0);cout<<vNumCanUse.at(1);}else if(k == 2){cout<<vNumCanUse.at(1);cout<<vNumCanUse.at(0);}elsecerr<<"Error In Convert !"<<endl;cout<<endl;return 0;}

原创粉丝点击