洛谷P1157 组合的输出-二进制

题目描述

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r ≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。

现要求你输出所有组合。

例如n=5,r=3,所有组合为:

12 3 , 1 2 4 , 1 2 5 , 1 3 4 ,1 3 5 , 1 4 5 , 2 3 4 , 2 3 5 , 2 4 5 , 3 4 5

输入格式

一行两个自然数n,r(1<n<21,1≤r≤n)。

输出格式

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。

**注意哦!输出时,每个数字需要33个场宽,pascal可以这样:

write(ans:3);

输入输出样例

输入 #1

5 3 

输出 #1

  1  2  3
  1  2  4
  1  2  5
  1  3  4
  1  3  5
  1  4  5
  2  3  4
  2  3  5
  2  4  5
  3  4  5

解决方法:

​  当然可以用递归解决,还有一种方法是用二进制的性质解决。

分析例子

​  由输入 5 3得到的输出结果我们可以知道可以用11100代表123等以此类推。(方便理解的方式是这样,用一个bool 型数组 data[5] 存储位置是否输出,输出内容为下标+1)。

​ 由给出的输出可以看出对应的二进制数为:
​ 1 2 3 -> 11100
​ 1 2 5 -> 11001
​ 1 3 4 -> 10110
 1 3 5 -> 10101
 1 4 5 -> 10011
 2 3 4 -> 01110
 2 3 5 -> 01101
 2 4 5 -> 01011
 3 4 5 -> 00111

上代码: 分析了本题输出对应的二进制,那么主要问题就是如何得到这个二进制->先看代码,根据代码慢慢解释。

void work_show(int n,int r)
{
	int max = 1 << n;
    
    
	for(int x = max-1;x >= 0;x--){			//1 -> 见代码下面的解释,下同
		int num = 0;
		for(int i = n-1;i >= 0;i--)			//2
			if((x>>i)&1)				
				num++;
			
		if(num == r){					
			for(int i = n-1;i >= 0;i--)		//3
				if((x>>i)&1)
					printf("%3d",n-i);
			printf("\n");
		}
	}
}

在解释程序之前先说一下整体思路: 因为00111、01011、···、10101、···、11100属于00000、00001、00010、···、11110、11111即 0 ~ 31,即 0 ~ 25-1(25 = 1 << 5),所以思路就是从0 ~ 2^5-1 的数中找出二进制符合1的个数等于3的,并按序输出。因为输出顺序是按照11100~00111的顺序来的,所以对应的整数应该倒序,即对应代码中的 (x = max -1; x >= 0;x–)

  1. 从2^n-1 ~ 0倒序遍历,num 记录当下 x 对应二进制中所含的 1 的个数。
  2. 数出x对应二进制中所含 1 的个数,为了解释清楚举个例子:11100,因为奇数即末尾为1的数 & 1 等于 1,相反偶数即末尾为 0 的数 & 1等于 0。所以要判断 11100 的最高位为多少可以让其右移4(即 n - 1)位之后 & 1,若等于 1 即该位为 1,相反则为 0。同理,要判断第二高位是否为1可以让其右移 3 位,所以 i 代表右移几位按 n-1 ~ 0 遍历。
  3. 若此时 x 对应的二进制数所含的 1 个数为 3,此时按该二进制数代表的序列输出。输出方式同 2 中的循环。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Drdajie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值