zoukankan      html  css  js  c++  java
  • 字符排列组合

    最近在网上看到个小学四年级的数学题,用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;        
             
    }
  • 相关阅读:
    定位练习
    解决 java.lang.RuntimeException: Unable to start activity ComponentInfo{...}
    开发日志09
    Could not resolve all artifacts for configuration ':classpath'.
    本周总结
    AutoCompleteTextView自动补全(开发日志08)
    实现地图的建议搜索并显示 SuggestionSearch
    SuggestionSearch(开发日志07)
    android studio 查看函数的解释及说明
    初步确定页面(开发日志06)
  • 原文地址:https://www.cnblogs.com/ideawu1001/p/2917725.html
Copyright © 2011-2022 走看看