M个元素中含有相同的元素,如何得到他们的全排列(不重复排列)?
元素表述: a1,a1,...a1, a2,a2,...a2,.......,an,an,...an
其中,a1的个数为N1, a2的个数为N2,以此类推,总个数为M。
则可以证明不重复的排列种类的数目: M!/(N1!*N2!*...*Nn!)
就是将N个数字做全排列。不过对于某些数字不能选择而已。
这里只要限制将要选择的数字必须大于原来已经选择的数字就可以达到目标。
下面是递归算法
#include <stdio.h>
#define N 5
void arrange(int rec[],int used[],int depth);
void write(int rec[], int maxdepth);
int a[N]={1,1,2,2,3}; //这些值必须升序排列且大于0
int count=0;
int main()
{int rec[N+1]={0},used[N+1]={0};
arrange(rec,used,0);
printf( "\ncount=%d ",count);
getchar();
return 0;
}
void write(int rec[])
{ int i;
for(i=0;i <N;i++)
printf( "%4d ",a[rec[i]]);
printf( "\n ");
count++;
}
void arrange(int rec[],int used[],int depth)
{
int i,found_num;
if (depth> =N) write(rec); //找到了一个可行解,输出
else
{found_num=0; //增加这个变量记录原来本结点存储的数字
for(i=0;i <N;i++) // 搜索该结点的孩子结点
{//如果该下标在前面还没有使用过,且该下标所指示的数字比
//原先所放置的数字要大,则是一个部分解
if(used[i]==0 && a[i]> found_num )
{ rec[depth]=i; //记录下该结点放置的下标
found_num=a[i]; //记录下本结点存放的数字
used[i]=1; // 标记该下标已经被使用
arrange(rec,used,depth+1); // 扩展,进入孩子结点继续搜索
used[i]=0; //退回来后要清除本结点所记录下标的使用记录
}
}
}
}