字符排列组合

最近在网上看到个小学四年级的数学题,用1~8这8个数字构成两个四位数,每个数字只能使用一次,要求其中一个四位数是另一个四位数的4倍,求出这两个数。算了一会,没得啥子思路,感觉要试很多次才搞得出来,索性就编个程序算。解决这个问题的主要方向就是排列组合的问题,列出所有的组合,然后将字符数组转换为数字,找出符合关系的数字即为答案。

计算出来有两组答案,7452=1863*4,5472=1368*4。

根据百度文库里面有一篇文章讲解字符排列组合的算法,如

a

ba ab

cba cab bca acb bac abc

......以此类推。此算法就是利用上一次排列的结果,根据新加入的元素插入的位置来组织数据在内存中的存放。例如第三排我们是根据第二排的结果,将c插入到组合的第一个,第二个,第三个位置才产生了第三排的结果,这样的算法就很有规律了。

从上面的分析我们可以看出,该算法在写程序时就是要使用递归来实现,根据上一层的结果来做当前的计算。既然是递归,我们肯定先需要一种base情况,我们就用字符数量为2的就行,这时直接用四个赋值就可以完成递归初始化情况的。

对于递归情况相较而言稍微麻烦一点。首先我们要申请足够的内存来存放数据,对于n个不同的字符进行排列组合,有n!种不同的情况,对于每一种情况需要n个字节来存放,所以为存放最终结果我们需要申请n!*n个字节的内存,而上一次的结果是一段(n-1)!*(n-1)个字节,接下来要做的就是内存数据的复制和新数据的插入。

为了完成复制和插入,我们将会好好利用/和%两个运算。针对复制和插入的过程就是对新申请的内存的一个一个的赋值,我们利用下标访问的方法进行操作(设下标为j),利用if(j/n!==k)(k代表新数据插入位置)的结果确定的j值(满足该条件的j值是一段数值,且连续),表明这一段内存中的数据,新数据都插入到第k个位置。找到了该段内存之后,我们就要决定里面哪些值赋新数据,哪些进行copy。我们再用if(j%n!==k)即判断该下标的位置是否是插入新数据,如果不满足就进行内存copy,将PreResult里的东西copy过来。

全部代码如下:

#include <stdlib.h>
#include <malloc.h>
#include <iostream>
using namespace std;

#define LEN 8
char str[LEN]={'1','2','3','4','5','6','7','8'};
//unsigned int value[LEN]={1,2,3,4,5,6,7,8};
char* test(char* source,unsigned int n);
unsigned int ChartoInt(char* original);
void main()
{
    char* p;
    unsigned int n;
    unsigned int j;
    unsigned int length=1;
    cin>>n;
    for(j=1;j<n+1;j++)
    {
        length=length*j;
    }
    p=test(str,n);
  
  for(unsigned int i=0;i<length;i++)
  {
      if(
          ChartoInt(p+i*8+0)==4*ChartoInt(p+i*8+4)
          )
          cout<<ChartoInt(p+i*8+0)<<ChartoInt(p+i*8+4);
      }
    //for(int i=0;i<n*length;i++)
    //{
    //    cout<<*(p+i);

    //}
    //cout<<*p<<*(p+1)<<*(p+2)<<*(p+3)<<*(p+4)<<*(p+5)<<*(p+6)<<*(p+7)<<*(p+8)<<*(p+9)<<*(p+10)<<*(p+11)<<*(p+12)<<*(p+13)<<*(p+14)<<*(p+15)<<*(p+16)<<*(p+17);
    while(1);
}

char* test(char* source,unsigned int n)
{
    unsigned int i;//to be used in caculate n!
    unsigned int length=1;//the new memory to allocate
    
    unsigned int j;// to be used in classify the positon to insert new data
    unsigned int k;
    unsigned int count;
    char* CurrentMemory;
    //char* PreSource;
    char* PreResult;
    //char* PreSource=&source[0];
    if(2==n)//this is the base condition
        {
            CurrentMemory=(char*)malloc(sizeof(char)*4);
            *CurrentMemory=*(source+1);
            *(CurrentMemory+1)=*source;
            *(CurrentMemory+2)=*source;
            *(CurrentMemory+3)=*(source+1);
            return CurrentMemory;
        }
    else
    //this is the recursive condittion            
      
      {
        for(i=1;i<n+1;i++)//to caculate n! 
          {
            length=length*i;
          }
          CurrentMemory=(char*)malloc(sizeof(char)*n*length);//allocate the memory needed to use  
          
          PreResult=test(source,n-1);
          
          
              for( k=0 ; k<n ; k++ )//k is to be used in define which block have the same position to insert the new data
              {
                  
                  unsigned int num=0;
                  for(j=0;j<length*n;j++)//j is the number of each data
                  {
                      if(j/length==k)//in each block what we should do,我们找到在第k个位置插入新数据的块,是满足这个if语句的,然后我们针对这块数据进行操作。这一大串for循环找到的东西就是满足条件的下标,但是并没有做任何操作。
                      {
              
                       
                       if(j%n==k)//要插入新数据的位置
                       {
                           CurrentMemory[j]=source[n-1];
                           
                       }
                           else//需要从上一次的结果中复制数据到新开辟的内存中来
                        {
                            CurrentMemory[j]=PreResult[num];
                            num++;
                        }

                      }
                  }
              }

              free(PreResult);
          return CurrentMemory;
      }      
        
    }

unsigned int ChartoInt(char* original)
{
         unsigned int Result;
         Result=(unsigned int)((*original)-0x30)*1000+
                (unsigned int)((*(original+1))-0x30)*100+
                (unsigned int)((*(original+2))-0x30)*10+
                (unsigned int)((*(original+3))-0x30);
         return Result;        
         
}
原文地址:https://www.cnblogs.com/ideawu1001/p/2917725.html