51nod 1384 可重集的全排列
阅读原文时间:2023年07月10日阅读:1

对于1231,121,111等有重复的数据,我们怎么做到生成全排列呢

实际上,对于打标记再释放标记的这种方法,如果一开始第一层递归访问过1那么你再访问

就会完全重复上一次1开头的情况,那么递归地考虑这件事,我们发现不需要重复相同的开头

但这样可能会重复一个数字过多次数,比如121,第一层2,第二层可能是2,第三层可能也是2

那么我们怎么解决这个呢,一个笨办法是统计原数组该值出现几次,现有生成的数列里出现了几次,

那么比较一下大小,我们就知道能不能放

关于不放重复开头这件事,我们可以对原序列排序,于是相同的值相邻,那么我们在实现中,每次跳过相同的一段即可

附上代码,由于输出量巨大,所以…cstdio TLE,stdio.h AC

1 #include
2 #include
3 #include
4 using namespace std;
5 char s[100];
6 int num[100],sz,A[100]; 7 void dfs(int cur){
8 if(cur==sz){
9 for(int i=0;i<sz;++i) printf("%d",A[i]);printf("\n");
10 }
11 else for(int i=0;i<sz;++i){
12 if(!i||(num[i]!=num[i-1])){
13 int c1=0,c2=0;
14 for(int j=0;j<cur;++j) if(num[i]==A[j]) c1++;
15 for(int j=0;j<sz;++j) if(num[i]==num[j]) c2++;
16 if(c1<c2){
17 A[cur]=num[i];dfs(cur+1);
18 }
19 }
20 }
21 }
22 int main(){
23 scanf("%s",s);
24 sz=strlen(s);
25 for(int i=0;i<sz;++i) num[i]=s[i]-'0';
26 sort(num,num+sz);
27 dfs(0);
28 return 0;
29 }