组合型和排列型枚举

2024-03-31 13:20
文章标签 枚举 排列 组合型

本文主要是介绍组合型和排列型枚举,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

组合型枚举

排列组合是大家都接触过的概念,而组合型枚举则是在 n 个元素中随机选出 m 个元素的问题。对于每一种可能的选择方案,我们需要确定选择了哪 m 个元素,这就是组合型枚举。
组合型枚举有一套固定的流程和算法模板,需要大家进行记忆。

chosen = []
n = 0
m = 0def calc(x):if len(chosen) > m:returnif len(chosen) + n - x + 1 < m:returnif x == n + 1:for i in chosen:print(i,end=' ')print('')returnchosen.append(x)calc(x + 1)chosen.pop()calc(x + 1)if __name__ == '__main__':tem = input().split()n = int(tem[0])m = int(tem[1])calc(1)

题目:公平抽签

题目描述:

小 A 的学校,蓝桥杯的参赛名额非常有限,只有 m 个名额,但是共有n 个人报名,其中 m≤n。作为老师非常苦恼,他不知道该让谁去,他在寻求一个绝对公平的方式。于是他准备让大家抽签决定,即 m 个签是去,剩下的是不去。小 A 非常想弄明白最后的抽签结果是什么样子的,到底有多少种结果。

请设计一个程序帮助小 A。最后输出各种情况的人名即可,一行一种情况,每种情况的名字按照报名即输入顺序排序。

第一行 输入 N,M。

第二行 到第 N+1 行 共输入 N 个人名每种情况输出 M 个人名,空格隔开。

样例:

输入:3  2
xiaowang
xiaoA
xiaoli
输出:xiaowang xiaoA
xiaowang xiaoli
xiaoA xiaoli

题目解析:

实际上还是组合型枚举,但是输出元素为人名,我们可以将人名存起来,输出的时候,根据数字下标找到提前存好的人名,直接输出即可。

#include <iostream>
#include <vector>
using namespace std;int n; //共计N个数
int m; //选m个数
vector<string> name;
vector<string> ans;
vector<int> chosen;
void calc(int x)
{if (chosen.size() > m || chosen.size() + (n - x + 1) < m) //剪枝return;if (x == n + 1){ //选够了m个数输出string ansTem = "";for (int i = 0; i < chosen.size(); i++)ansTem += name[chosen[i] - 1] + " ";ans.push_back(ansTem);return;}chosen.push_back(x);calc(x + 1);chosen.pop_back(); //消除痕迹calc(x + 1);}
int main()
{cin >> n >> m;for (int i = 0; i < n; i++){string s;cin >> s;name.push_back(s);}calc(1);for (int i =0; i < ans.size(); i++)cout << ans[i] << endl;
}

排列型枚举

上面说过,组合型枚举就是让你在 n 个中,随机选出 m 个 ,问你有多少种方案,而且每一种方案选择了哪 m  个,这就是组合型枚举。

而排列型枚举相对组合型枚举就简单了一点,就是n 个的全排列,即从 n 个中选取 n 个但是关心内部的顺序。

相比较组合只关心有多少个集合,而排列是关心集合内的排列方式。即排列型枚举就是寻找Ann问题。

而且排列型枚举也是有着比较成熟的模板需要大家进行记忆。

int n; //共计N个数
int order[20];
bool chosen[20];
void calc(int k)
{if (k == n + 1){for (int i = 1; i <= n; i++)cout << order[i] << " ";puts("");return;}for (int i = 1; i <= n; i++){if (chosen[i])continue;order[k] = i;chosen[i] = 1;calc(k + 1);chosen[i] = 0;order[k] = 0;}
}
int main()
{cin >> n;calc(1);
}

座次问题

题目描述:

小 A 的学校,老师好不容易解决了蓝桥杯的报名问题,现在老师又犯愁了。现在有 N 位同学参加比赛,但是老师想给他们排座位,但是排列方式太多了。老师非常想弄明白最后的排座次的结果是什么样子的,到底有多少种结果。

请设计一个程序帮助老师。最后输出各种情况的人名即可,一行一种情况,每种情况的名字按照报名即输入顺序排序。第一行 输入 N; 第二行 到 第 N+1 行 共输入 N 个人名。由于小 A 学校承办能力实在有限,所以其中 N 小于等于 10 人。

输入:3
xiaowang
xiaoA
xiaoli
输出:xiaowang xiaoA xiaoli
xiaowang xiaoli xiaoA
xiaoA xiaowang xiaoli
xiaoA xiaoli xiaowang
xiaoli xiaowang xiaoA
xiaoli xiaoA xiaowang

代码:

#include <iostream>
#include <vector>
using namespace std;int n; //共计N个数
vector<string> name;
int order[20];
bool chosen[20];
void calc(int k)
{if (k == n + 1){for (int i = 1; i <= n; i++)cout << name[order[i] - 1] << " ";puts("");return;}for (int i = 1; i <= n; i++){if (chosen[i])continue;order[k] = i;chosen[i] = 1;calc(k + 1);chosen[i] = 0;order[k] = 0;}
}int main()
{cin >> n;for (int i = 0; i < n; i++){string s;cin >> s;name.push_back(s);}calc(1);
}

 

这篇关于组合型和排列型枚举的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/864437

相关文章

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d

hdu 6198 dfs枚举找规律+矩阵乘法

number number number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description We define a sequence  F : ⋅   F0=0,F1=1 ; ⋅   Fn=Fn

【Rust练习】12.枚举

练习题来自:https://practice-zh.course.rs/compound-types/enum.html 1 // 修复错误enum Number {Zero,One,Two,}enum Number1 {Zero = 0,One,Two,}// C语言风格的枚举定义enum Number2 {Zero = 0.0,One = 1.0,Two = 2.0,}fn m

枚举相关知识点

1.是用户定义的数据类型,为一组相关的常量赋予有意义的名字。 2.enum常量本身带有类型信息,即Weekday.SUN类型是Weekday,编译器会自动检查出类型错误,在编译期间可检查错误。 3.enum定义的枚举类有什么特点。         a.定义的enum类型总是继承自java.lang.Enum,且不能被继承,因为enum被编译器编译为final修饰的类。         b.只能定义

PHP字符串全排列

方法一: $str = 'abc';$a =str_split($str);perm($a, 0, count($a)-1);function perm(&$ar, $k, $m) {if($k == $m){ echo join('',$ar), PHP_EOL;}else {for($i=$k; $i<=$m; $i++) {swap($ar[$k], $ar[$i]);perm($ar

回溯——9.全排列

力扣题目链接 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3]输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 解题思路 问题建模:题目要求给出一个数组的所有排列组合,属于典型的全排列问题,这可以用回溯法来解决。回溯法通过递归的方式,依次将数组中的每个元素放入排列中,直到生成

【C语言】结构体、枚举、联合体

【C语言】结构体、枚举、联合体 文章目录 @[TOC](文章目录) 前言一、结构体声明1.一般格式2.typedef 重命名结构体类型定义变量 二、结构体数组三、结构体与指针及函数传参四、结构体传参五.结构体在内存的存储六、参考文献总结 前言 使用工具: 1.编译器:VScode 2.C Primer Plus 第六版-1 提示:以下是本篇文章正文内容,下面案例可供参考

代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II

代码随想录刷题day25丨491.递增子序列 ,46.全排列 ,47.全排列 II 1.题目 1.1递增子序列 题目链接:491. 非递减子序列 - 力扣(LeetCode) 视频讲解:回溯算法精讲,树层去重与树枝去重 | LeetCode:491.递增子序列_哔哩哔哩_bilibili 文档讲解:https://programmercarl.com/0491.%E9%80%92%E

python 实现第k个字典排列算法

第k个字典排列算法介绍 "第k个字典排列"算法通常指的是在给定的字符集合(例如,字符串中的字符)中,找到所有可能排列的第k个排列。这个问题可以通过多种方法解决,但一个常见且高效的方法是使用“下一个排列”算法的变种,或称为“第k个排列”的直接算法。 方法一:使用“下一个排列”的变种 生成所有排列:首先生成所有排列,但显然这种方法对于较大的输入集合是不切实际的,因为它涉及到大量的计算和存储。 排序

10730-Antiarithmetic?【暴力枚举】

水题 求一个序列是否存在3个数按顺序构成等差数列 直接枚举等差数列的差值 时间复杂度降到 n * n / 3 开pos数组记录每个值得为之 楷vis数组记录目前i是否出现过 强行AC 15221397 10730 Antiarithmetic? Accepted C++ 0.035 2015-03-26 12:09:56 #include<cstdio>#include