设有{r1,r2,...,rn}共n个元素,这n个元素中可能存在重复元素,试设计一个算法,列出这n个元素的不同排列。
下面有三种实现方法,前两种是对应的字符串,最后一种后来写的关于数字的
没啥好说的,调用STL库中的函数
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
#define ll long long
const int INF=0x7fffffff;
const int N=101;
char a[N],temp[N],b[N];
int vis[N],n;
int main()
{
int i;
while (~scanf("%d",&n))
{
getchar();
for (i=0;i<n;i++)
scanf("%c",&a[i]);
sort(a,a+n);
int cnt=0;
do{
puts(a);
cnt++;
}while(next_permutation(a,a+n));
printf("%d\n",cnt);
}
}
核心思想就是判断两个数量,一个是某个元素在当前生成的集合中出现的次数,另一个是该元素在完整集合中出现的次数,如果一样,那就说明重复了,不在往下遍历了。#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
#define ll long long
const int INF=0x7fffffff;
const int N=101;
char a[N];
int n,cnt,b[N];
void dfs(int cur)
{
if (cur==n)
{
cnt++;
for (int i=0;i<n;i++)
printf("%c",b[i]+'a');
printf("\n");
}
else for (int i=0;i<n;i++) //刘汝佳书上的
if (!i||a[i]!=a[i-1])
{
int c1=0,c2=0;
for (int j=0;j<cur;j++)
if (b[j]==a[i]-'a')
c1++;
for (int j=0;j<n;j++)
if (a[j]==a[i])
c2++;
if (c1<c2) //如果它们个数相等的话,就不做递归操作
{
b[cur]=a[i]-'a';
dfs(cur+1);
}
}
}
int main()
{
int i;
while (~scanf("%d",&n))
{
getchar();
for (i=0;i<n;i++)
{
scanf("%c",&a[i]);
b[i]=a[i]-'a';
}
dfs(0);
printf("%d\n",cnt);
}
}
核心思想:用全排列把所有可能都暴力出来,然后用个判断函数检查区间[s,e)里面有没有出现关于a[e]重复的,出现重复说明以前有过这样的全排列,直接不在往下遍历,换另一种。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define M 1001
using namespace std;
int a[M],n;
int check(int s,int e)
{
int i;
for (i=s;i<e;i++)
if (a[i]==a[e])
return 0;
return 1;
}
void dfs(int cur)
{
int i;
if (cur==n)
{
for (i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
for (i=cur;i<=n;i++)
if (check(cur,i))
{
swap(a[i],a[cur]);
dfs(cur+1);
swap(a[i],a[cur]);
}
}
int main()
{
int i;
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs(1);
return 0;
}