对排列组合的理解

       全排列的意思大家也许都很明白,但是,如果用编程来实现的话,那你会不会觉得很难呢?也许会。我以前在看到全排列的题目时,我觉得非常的害怕,因为这么多的数或元素怎么实现全排列啊,真觉得不可思议。以前就是会想,如果求全排列的个数的话,那就容易的多啊,就是阶乘问题。但是现在不是叫你求出个数,而是求出全排列把并且输出来。这个问题一开始真的 不知所措。虽然网上有很多人发表对全排列的理解及相关算法的实现,但是根本没有说到要点,所以对于一个初学者来时是如此的难理解。全排列在算法里有两个经典的算法实现,但在这里不多说。因为我就今天看过了全排列的算法和别人对算法的的理解,但是很多人没有把算法说得很好,并且写出很好理解的算法程序。在我搜查排列组合算法其中,个人觉得写得最为好理解的排列组合算法就为下面其中几个,这几个这个作者所写的算法,请点击这里。 这边文章的排列组合算法非常容易理解,很符合我们常人的思维理解,只要你对递归有所了解或者对图的深度优先搜索算法理解,那么这几个算法你将会一看就明白。吹水就不吹那么多了,先说说我对这几个算法的理解吧,我也是刚看到这些算法的,所以对其的理解有很大的不足之处,请指点。

        下面是不可重组合的组合算法,因为所用集合不允许有重复的元素,排列出来的各种组合的每个元素均不相同,并且组合出来的集合的元素都不能完全一样,这是集合的特点,组合就是能有多少个不同的集合的情况。

       该算法的思想很简单,就是输入一个数n,和集合大小r,然后通过我们所熟悉的深度优先搜索方式去递归枚举出所有组合结果。我们将每次递归的结果放到数组a中,并且用数组used标志当前元素是否在集合a中,如果在那就放弃,继续放其他元素,知道将集合放满r个为止。另外,为了使排列结果以连续的数开始,在遍历时采用一个参数pos传递所遍历到的位置,这样一开始决定了组合数的开始数是连续的。为了能使得得出的组合没有重复的集合,那么使用n-r+pos  作为遍历数组的下届,这样一来最多只可以遍历r个元素,不明白的可以自己慢慢考虑这个问题,因为这也是值得去思考的问题。

int a[10], used[10] = {0}, n , r ;
void zhs(int pos,int h)
{
	if (r==pos)
	{
		for (int i = 0; i < r; i++)
		{
			printf("%d",n-a[i]);
		}
		printf("\n");
	}
	else
	{
		for (int i =h; i<=n-r+pos  ; i++)
		{
			if (!used[i])
			{
				used[i]++;
				a[pos] = i;
			    zhs(pos+1,i+1);
				used[i]--;
			}
		}
	}
}


        其实排列和组合是差不多的,只是在限制其重复元素的不同而已。排列就只是让一个集合含有的元素不重复,但是可以允许两个集合无序重复,这恰恰就是排列的特点,因此,我们只需在组合算法上修改一点即可,复杂的限制条件不需要添加了,就只需要判断该元素是否存在于当前集合就可。但是,要注意的是:每当一个集合存放元素完毕,那么就必须将该元素的被使用标志去掉,这样就可以让下一个集合正常使用。这样一说,应该不难明白吧。


int a[10], used[10] = { 0 }, n , r ;
//int p=1;
void zhs(int pos)
{
	if (r == pos)
	{
		//printf("%d:",p);
		for (int i = 0; i < r; i++)
		{
			printf("%d",n-a[i]);
		}
		//p++;
		printf("\n");
		return;
	}
	else
	{
		for (int i = 0; i < n; i++)
		{
			if (!used[i])
			{
				used[i]++;
				a[pos] = i;
				zhs(pos + 1);
				used[i]--;
			}


		}
	}
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值