排列组合算法笔记

来源:互联网 发布:网络市场具体有哪些 编辑:程序博客网 时间:2024/04/29 12:40

1.不存在重复字符的排列组合

如abc,此种情况很简单,算法代码也很少,主要思想为:

  • 将abc分为前部和后部,前部为a,后部abc,用a与后部每一个字符交换,如a<->a得到abc,a<->b得到bac,a<->c得到cba,最终得到abc,bac,cba三部分
  • 针对上一部分中的三个后部,分别继续应用分两部,分别交换的方法,直到后部为NULL,递归输出字符串。
上述方法的递归代码如下:

#include<iostream>using namespace std;void swap(char *pChar1,char *pChar2){char temp;temp=*pChar1;*pChar1=*pChar2;*pChar2=temp;}void FullArry(char *cStr,char *pFirstChar){char *pNode;if(NULL==cStr)return;if('\0'==*pFirstChar){cout<<cStr<<endl;}for(pNode=pFirstChar;*pNode!='\0';pNode++){swap(pFirstChar,pNode);FullArry(cStr,pFirstChar+1);swap(pFirstChar,pNode);}return ;}int main(){char a[10000];cin>>a;FullArry(a,a);return 0;}
输入abc,结果为:

如果输入abb

2.存在重复字母的排列组合

结果显然不符合要求,原因是因为 1.前部与后部相同的情况,我们进行了对换。2.后部如果有多个字符相同,只需要在该字符第一次出现的时候对换前后部字符。

针对上述的情况,修改代码如下:

#include<iostream>using namespace std;void swap(char *pChar1,char *pChar2){char temp;temp=*pChar1;*pChar1=*pChar2;*pChar2=temp;}bool CheckHasSame(char *pHead,char *pValue){if('\0'==*pHead)return true;while(pHead!=pValue){if(*pHead==*pValue)return true;pHead++;}return false;}void FullArry(char *cStr,char *pFirstChar){char temp,*pNode;if(NULL==cStr)return;if('\0'==*pFirstChar){cout<<cStr<<endl;}pNode=pFirstChar;if(*pNode!='\0')//此部分为前部和后部首字母相同的特殊情况,单独处理{swap(pFirstChar,pNode);FullArry(cStr,pFirstChar+1);swap(pFirstChar,pNode);pNode++;}for(;*pNode!='\0';pNode++){if(!CheckHasSame(pFirstChar,pNode))//保证后部待交换字符在后部首次出现{swap(pFirstChar,pNode);FullArry(cStr,pFirstChar+1);swap(pFirstChar,pNode);}}return ;}int main(){char a[10000];cin>>a;FullArry(a,a);return 0;}

输入abb,结果为


3.求abc的所有组合,即a,b,c,ab,ac,bc,abc

第一种方法:

假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。下面是这种思路的参考代码:

#include<iostream>#include<vector>using namespace std;vector<char> vStr;template<typename T>void PrintAllMember(const vector<T> &t_toPrintOut,size_t Num){for(size_t i=0;i<Num;i++)cout<<t_toPrintOut[i];cout<<endl;return ;}void AllCombine(char *cStr,int n){if(0==n) {PrintAllMember<char>(vStr,vStr.size());return ;}if('\0'==*cStr)return;vStr.push_back(*cStr);AllCombine(cStr+1,n-1);vStr.pop_back();AllCombine(cStr+1,n);}int main(){char a[1000];cin>>a;int n=strlen(a);for(int i=1;i<=n;i++)AllCombine(a,i);return 0;}



总结上述成果解决两个问题:

1,八皇后问题

题目:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。


代码如下:借鉴了全排列问题求解;

#include<iostream>using namespace std;bool RuleCheck(int arr[],int arrlen){for(int i=0;i<arrlen;i++)for(int j=i+1;j<arrlen;j++){if(i-j==arr[i]-arr[j]||i-j==arr[j]-arr[i])return false;}return true;}void Print(int arr[],int arrlen){for(int i=0;i<arrlen;i++){cout<<arr[i];}cout<<endl;return;}template <typename T>void Swap(T &t_1,T &t_2){T t;t=t_1;t_1=t_2;t_2=t;}void EigthQueen(int arr[],int arrlen,int m){if(m==arrlen){if(RuleCheck(arr,arrlen))Print(arr,arrlen);return;}for(int i=m;i<arrlen;i++){Swap(arr[i],arr[m]);EigthQueen(arr,arrlen,m+1);Swap(arr[i],arr[m]);}return ;}int main(void){int a[7]={0,1,2,3,4,5,6,7};EigthQueen(a,8,0);return 0;}

2.输入n和m,求n到m上任意个数和等于m的情况

代码下,此题使用组合问题方法:

#include<iostream>#include<vector>using namespace std;vector<int> vArr;bool RuleCheck(vector<int> &v,int m){vector<int>::iterator it;it=v.begin();size_t result=0;while(it!=v.end()){result+=*it;it++;}if(m==result)return true;elsereturn false;}void Print(vector<int> &v){vector<int>::iterator it;it=v.begin();while(it!=v.end()){cout<<*it<<" ";it++;}cout<<endl;return;}void SumIsM(int headArr,int endArr,int numOfArr){if(endArr-headArr<numOfArr-1)return;if(0==numOfArr){if(RuleCheck(vArr,endArr))Print(vArr);return ;}vArr.push_back(headArr);SumIsM(headArr+1,endArr,numOfArr-1);vArr.pop_back();SumIsM(headArr+1,endArr,numOfArr);}int main(void){for(int i=1;i<=5;i++)SumIsM(1,5,i);return 0;}




0 0
原创粉丝点击