数的全排列和 避免重复运,top之前不入栈,还有求n的数子集,不是全排列了,而是每个数选或不选的问题
来源:互联网 发布:js substring的用法 编辑:程序博客网 时间:2024/06/02 05:11
输入一个数n,下面输入n个数,求n个数的全排列;
代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define Max 50int book[Max],tt[Max];int a[Max],n;void dfs(long long x ){if(x>n){for(int i=1;i<=n;i++){if(i==n) printf("%d\n",tt[i]);else printf("%d ",tt[i]);}return ;} for(int i = 1; i<=n; i++) { if(!book[i]) { book[i] = 1; tt[x] = a[i]; dfs(x+1); book[i] = 0; } }}int main(){ while(~scanf("%d",&n)) { for(int i=1; i<=n; i++) scanf("%d",&a[i]); memset(book,0,sizeof(book)); dfs(1); } return 0;}
也可以直接用c++的函数库中的全排列函数 next_permutaton(a,a+n,cmp);
cmp,可加可不加,不加就是全排列,加上,就是自己定义一个cmp函数,按照自己定义的函数里的return条件,所排列;
下面一个n,输入n个数,求n的数的子集
思路:可以用全排列求:但像1,2,3 和 3,2,1 和2,1,3 ...,这些只要其中的一组就行了
所以可以在存到数组中时,加上一个条件,代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define Max 50int book[Max],tt[Max];int a[Max],n;void dfs(long long x ){ for(int i = 1; i<=n; i++) { if(!book[i]&&tt[x-1]<=a[i]) { book[i] = 1; tt[x] = a[i]; for(int j = 1;j <=x;j++) { if(j==x) printf("%d\n",tt[j]);else printf("%d ",tt[j]); } dfs(x+1); book[i] = 0; } }}int main(){ while(~scanf("%d",&n)) { for(int i=1; i<=n; i++) scanf("%d",&a[i]); memset(book,0,sizeof(book)); dfs(1); } return 0;}
加上一个条件 a[x-1]<=a[i] ,这个条件使得tt[] 数组中存的数是递增的;这样就避免重复子集的发生;
也可以这样 定义 一个 top 在 top 之前的数,都不在进入栈中这样可以避免重复
和上一个条件的区别就是 上一个输出的数单调递增的,而这个是取决于输入n的数的顺序,在top之前的数是不可以在进栈,不可在进入tt[] 数组中
代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define Max 50int book[Max],tt[Max];int a[Max],n;void dfs(int top,int x ){ for(int i = top; i<=n; i++) { if(!book[i]) { book[i] = 1; tt[x] = a[i]; for(int j = 1;j <=x;j++) { if(j==x) printf("%d\n",tt[j]);else printf("%d ",tt[j]); } dfs(i+1,x+1); book[i] = 0; } }}int main(){ while(~scanf("%d",&n)) { for(int i=1; i<=n; i++) scanf("%d",&a[i]); memset(book,0,sizeof(book)); dfs(1,1); } return 0;}
以后避免像1,2,3 或3,2,1或2,1,3等这6种排列,只需要其中的一种就行了,以后就这样,简化上一个代码,仔细想想,top 之前的都不会再入栈了,那么book数组加不加是不是不起作用了,避免重复最简代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define Max 50int book[Max],tt[Max],num;int a[Max],n;void dfs(int top,int x) // 为了避免重复,定义了一个top,在top之前的都不在入栈; { // 那每个数还用不用标记了,答案是不用了,根本遍历不到在它之前的数,所以根本就不用book[]数组标记了 for(int i = top; i<=n; i++) { tt[x] = a[i]; for(int j = 1;j <=x;j++) { if(j==x) printf("%d\n",tt[j]);else printf("%d ",tt[j]); } dfs(i+1,x+1); }}int main(){ while(~scanf("%d",&n)) { for(int i=1; i<=n; i++) scanf("%d",&a[i]); memset(book,0,sizeof(book)); dfs(1,1); } return 0;}
可以仔细想想, 求子集用不用在每一栈中都遍历n个数,假设这n个数都满足条件,这不是每一栈都要递归n次后,才能结束吗,这时间复杂度太大了, 其实 求子集无非就是这个数选于不选的问题,定义一个光标top,当移动到这数时,这个数就两种情况 选或者不选,每个数的两种情况懂遍历完,不就可以了吗;
代码:
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define Max 50int book[Max];int a[Max],n;void dfs(int top) // 这个top可以比作为一个光标,这一行前后移动, { // 移动到这个数,这个数就有两种情况 选或者不选; if(top>n){int f =0;for(int j = 1;j <=n;j++) { if(book[j]) { if(!f){printf("%d",a[j]);f = 1; } else printf(" %d",a[j]); }}if(f) printf("\n");return ;}book[top] = 1; //这个数标记一下,选了 dfs(top+1); book[top] = 0; //这个数变为不选; dfs(top+1);}int main(){ while(~scanf("%d",&n)) { for(int i=1; i<=n; i++) scanf("%d",&a[i]); memset(book,0,sizeof(book)); dfs(1); } return 0;}
阅读全文
0 0
- 数的全排列和 避免重复运,top之前不入栈,还有求n的数子集,不是全排列了,而是每个数选或不选的问题
- 求数的全排列
- 数的全排列
- 数的全排列
- 数的全排列
- 数的全排列
- 数的全排列
- 数的全排列
- 数的全排列
- 数的全排列
- 求1-n的数的全排列
- 一个数n的全排列&&DFS
- 输出一个数n的全排列
- 求一列数的全排列
- 全排列数的生成
- 递归求重复数全排列;
- 输入一个数n,输出1~n的全排列
- 求不重复数据的全排列
- Dungeon Master(广搜)
- HDU3335-Divisibility
- 208. Implement Trie (Prefix Tree)
- HDU 4455 Substrings
- 二.Spring概念
- 数的全排列和 避免重复运,top之前不入栈,还有求n的数子集,不是全排列了,而是每个数选或不选的问题
- JSP入门
- oracle学习(使用了PL/SQL)——3
- 集合
- 找第几个兄弟节点
- retrofit的 get post 请求 + log日志
- mina相关应用
- CDH(Cloudera)与hadoop(Apache)对比
- switch成绩