user-0 提问: 求解 一种 组合算法

回复:
user: user-1
content: 仅供参考#include <stdio.h> #include <stdlib.h> #define MAX_NUM 26 int comb[MAX_NUM]; int c1,c2; void combination(int m,int n) {     int i,j;      for (i=m;i>=n;i--) {         comb[n]=i; /* 选择当前的“头”元素 */         if (n>1) {             combination(i-1,n-1); /* 进入下一次更小的组合问题 */         } else { /* 满了需要的组合数，输出 */             for (j=comb[0];j>0;j--) printf("%c",'A'+c1-comb[j]);             printf("\n");         }     }     return; } int main(int argc,char **argv) {     if (argc<3) {         printf("%s 组合下标 组合上标\n",argv[0]);         return 1;     }     c1=atoi(argv[1]);     if (c1<1 || MAX_NUM<c1) {         printf("1<=组合下标<=%d\n",MAX_NUM);         return 2;     }     c2=atoi(argv[2]);     if (c2<1 || c1<c2) {         printf("1<=组合上标<=组合下标\n");         return 3;     }     comb[0]=c2;     combination(c1,c2);     return 0; }

user: user-0
content: 引用 7 楼 misakamm 的回复:[quote=引用 5 楼 litianyiliwei 的回复:] [quote=引用 4 楼 misakamm 的回复:] [quote=引用 3 楼 litianyiliwei 的回复:] [quote=引用 1 楼 misakamm 的回复:] http://baike.baidu.com/view/4084060.htm 以上为正解，给分吧  我不是要生成多少个，而是所有组合!（不是“生成组合的数目”而是“生成所有组合”）[/quote] 在最顶楼你又没说，生成所有的那就没啥好说了，直接递归生成同时去重就是了[/quote]  既然是算法要求效率啊[/quote] 你生成全部那还有什么效率可言呢？你又不是计算个数，你在6楼的话简直是倒着说话不腰疼[/quote]  Sorry！确实说的话，不合适。

user: user-2
content: 想了一下，复杂度很高，要求所有的组合的话貌似还是递归搜索打印比较好，递归分别寻找： 全部为一个字母的情况， 有一个为两个字母的情况，有两个为两个字母的情况，有三个为两个字母的情况。。。。 。。。 有一个为n / 2 - 1字母的情况。  因为对于n / 2 ~ n之间的全部在前面已经包含了便不用计算  这个题目我在poj上做过，好像能够剪枝，等找到了再回复一次

user: user-3
content: 引用 10 楼 misakamm 的回复:[quote=引用 8 楼 waterSStreaming 的回复:] 卡特兰数, http://baike.baidu.com/view/1154333.htm 不是卡特兰数 [/quote] 哦，好像是我错了

user: user-2
content: 引用 12 楼 p569354158 的回复:想了一下，复杂度很高，要求所有的组合的话貌似还是递归搜索打印比较好，递归分别寻找： 全部为一个字母的情况， 有一个为两个字母的情况，有两个为两个字母的情况，有三个为两个字母的情况。。。。 。。。 有一个为n / 2 - 1字母的情况。  因为对于n / 2 ~ n之间的全部在前面已经包含了便不用计算  这个题目我在poj上做过，好像能够剪枝，等找到了再回复一次 找到了，POJ2531http://poj.org/problem?id=2531 该题目的意思是找到最大延迟子网划分方法，要找到最大延迟子网只能递归深搜，将所有结果搜索完之后便可知道最大延迟网络的划分方法，楼主的题目跟这个题目很像，希望参考。 附POJ2531 AC代码：  #include <iostream> #include <cstdio> #include <cstring> using namespace std;  int c[22][22], n, ans, set[22];  void DFS(int id, int sum) {     int i;      set[id] = 1;     for (i = 0; i < n; i++) {         if (set[i] == 1)             sum -= c[id][i];         else sum += c[id][i];     }     if (sum > ans) ans = sum;      for (i = id+1; i < n; i++)     {         DFS(i, sum);         set[i] = 0;     } }  int main() {     int i, j;      scanf ("%d", &n);     for (i = 0; i < n; i++)         for (j = 0; j < n; j++)              scanf ("%d", &c[i][j]);     memset (set, 0, sizeof (set));     ans = 0;     DFS(0, 0);     printf ("%d\n", ans);      return 0; }  下面是一个执行速度更快的版本：  #include<stdio.h> int map[25][25]; int in[25]; int out[25]; int n,ans; void dfs(int k,int s,int ni,int no) { 	int i,sum; 	if(s>=ans) 		return;         sum=0; 	for(i=1;i<=ni;i++) 		sum+=map[in[i]][k]; 	if(k==n) 	{ 		if(s+sum<ans) 			ans=s+sum; 	} 	else 	{ 		in[ni+1]=k; 		dfs(k+1,s+sum,ni+1,no); 	} 	sum=0; 	for(i=1;i<=no;i++) 		sum+=map[out[i]][k]; 	if(k==n) 	{ 		if(s+sum<ans) 			ans=s+sum; 	} 	else 	{ 		out[no+1]=k; 		dfs(k+1,s+sum,ni,no+1); 	} 	return; } int main() { 	int i,j,k,p=0,q=0; 	scanf("%d",&n); 	ans=0; 	for(i=1;i<=n;i++) 	{ 		for(j=1;j<=n;j++) 		{ 			scanf("%d",&map[i][j]); 			ans+=map[i][j]; 		} 	} 	k=ans/2; 	for(i=1;i<=n/2-1;i++) 	{ 		for(j=1;j<=n/2-1;j++) 			p+=map[i][j]; 	} 	p=p/2; 	for(i=n/2;i<=n;i++) 	{ 		for(j=n/2;j<=n;j++) 			q+=map[i][j]; 	} 	q=q/2; 	ans=p+q; 	in[1]=1; 	dfs(2,0,1,0); 	printf("%d\n",k-ans); 	return 0; }

user: user-4
content: 引用 8 楼 waterSStreaming 的回复:卡特兰数, http://baike.baidu.com/view/1154333.htm 不是卡特兰数

user: user-3
content: 找不同组合的话， 1. 先找出不同的全排列； 2. 对于每一个全排列，把两数之间的空当作0和1两种状态，0就是把左右并作一个，1就是把左右分到不同集合里去，例如a(0/1)b(0/1)c就有2个空，就有 a(0)b(0)c， a(0)b(1)c， a(1)b(0)c， a(1)b(1)c； 3. 最后去掉重复的组合方式。 这种是比较不考虑效率的方式，当然如果可以记录下一些中间结果以减少计算。

user: user-3
content: 卡特兰数, http://baike.baidu.com/view/1154333.htm

user: user-4
content: 引用 5 楼 litianyiliwei 的回复:[quote=引用 4 楼 misakamm 的回复:] [quote=引用 3 楼 litianyiliwei 的回复:] [quote=引用 1 楼 misakamm 的回复:] http://baike.baidu.com/view/4084060.htm 以上为正解，给分吧  我不是要生成多少个，而是所有组合!（不是“生成组合的数目”而是“生成所有组合”）[/quote] 在最顶楼你又没说，生成所有的那就没啥好说了，直接递归生成同时去重就是了[/quote]  既然是算法要求效率啊[/quote] 你生成全部那还有什么效率可言呢？你又不是计算个数，你在6楼的话简直是倒着说话不腰疼

user: user-0
content: 引用 4 楼 misakamm 的回复:[quote=引用 3 楼 litianyiliwei 的回复:] [quote=引用 1 楼 misakamm 的回复:] http://baike.baidu.com/view/4084060.htm 以上为正解，给分吧  我不是要生成多少个，而是所有组合!（不是“生成组合的数目”而是“生成所有组合”）[/quote] 在最顶楼你又没说，生成所有的那就没啥好说了，直接递归生成同时去重就是了[/quote]  不说效率，那我计算“多少个”，也可以“生成所有的那就没啥好说了，直接递归生成同时去重就是了”，然后再统计个数。也不用什么贝尔数算法了

user: user-0
content: 引用 4 楼 misakamm 的回复:[quote=引用 3 楼 litianyiliwei 的回复:] [quote=引用 1 楼 misakamm 的回复:] http://baike.baidu.com/view/4084060.htm 以上为正解，给分吧  我不是要生成多少个，而是所有组合!（不是“生成组合的数目”而是“生成所有组合”）[/quote] 在最顶楼你又没说，生成所有的那就没啥好说了，直接递归生成同时去重就是了[/quote]  既然是算法要求效率啊

user: user-4
content: 引用 3 楼 litianyiliwei 的回复:[quote=引用 1 楼 misakamm 的回复:] http://baike.baidu.com/view/4084060.htm 以上为正解，给分吧  我不是要生成多少个，而是所有组合!（不是“生成组合的数目”而是“生成所有组合”）[/quote] 在最顶楼你又没说，生成所有的那就没啥好说了，直接递归生成同时去重就是了

user: user-0
content: 引用 1 楼 misakamm 的回复:http://baike.baidu.com/view/4084060.htm 以上为正解，给分吧  我不是要生成多少个，而是所有组合!（不是“生成组合的数目”而是“生成所有组合”）

user: user-1
content: 生成组合的数目和生成所有组合不是一回事吧。

user: user-4
content: http://baike.baidu.com/view/4084060.htm 以上为正解，给分吧