关于枚举法及组合型、排列型枚举模板

枚举法

枚举算法的思想:

将问题的所有可能成为答案的解一一列举,然后根据问题所给出的条件判断此解是否合适,如果合适就保留,反之舍弃。

枚举算法解题的基本思路:

  • 确定枚举解的范围,以及判断条件
  • 选取合适枚举方法,进行逐一枚举,此时应注意能否覆盖所有的可能的解
  • 在枚举时使用判断条件检验,留下所有符合要求的解。

枚举算法的一般步骤:

  • 根据题目确定枚举的范围,并选取合适的枚举方式,不能遗漏任何一个真正解,同时避免重复。
  • 为了提高解决问题的效率,看题目是否存在优化,将可能成为解的答案范围尽可能的缩小。
  • 根据问题找到合理并、准确描述好编码的验证条件。
  • 枚举并判断是否符合第三步确定的的条件,并保存符合条件的解。
  • 按要求输出枚举过程中留下的符合条件的解。

简单型枚举

简单型枚举就是可以通过简单的 for 循环嵌套就可以解决的问题。

这种枚举方式没有特定的固定枚举方式,都比较简单,按照题目的要求进行设计代码即可完成解题。

42 点问题

众所周知在扑克牌中,有一个老掉牙的游戏叫做24点,选取4张牌进行加减乘除,看是否能得出24这个答案。
 现在小蓝同学发明了一个新游戏,他从扑克牌中依次抽出6张牌,注意不是一次抽出且不考虑10。进行计算,看是否能够组成 42 点,满足输出YES,反之输出 NO。
 最先抽出来的牌作为第一个操作数,抽出牌做第二个操作数,运算结果再当作第一个操作数,继续进行操作。
 除不尽的情况保留整数。
 请设计一个程序对该问题进行解答。

输入样例:
 K A Q 6 2 3  

输出样例:
 YES

运行限制:

最大运行时间:1s
最大运行内存: 128M

这里可以依次枚举数字,然后再枚举数字间的符号即可。创建 5 个 Vector,分别用来存放 1-5 次的运算结果

ans0内存放抽取的第一个数,ans1存放a[1]与下一个抽取的值经过加减乘除四种运算的结果(4种数据),ans2存放ans2中每一个数据各与再下一个抽取的值经过加减乘除四种运算的结果(4*4=16种)...以此类推,ans3内64种,ans4内256种,ans5内1024种。

注:’1‘的ASCLL码比‘0’的大1,'2'比'0'大2....所以如果所取牌的面值是数字c.charAt(0) - '0'得到的还是该数值。(把char类型的数字转换为int类型的数字,常用这种方法:c.charAt(0) - '0' )

代码如下:

import java.util.Scanner;
import java.util.Vector;public class Main {static int[] a = new int[10];static Vector> ans = new Vector>();public static void main(String[] args) {Scanner in = new Scanner(System.in);for (int i = 0; i < 6; i++) {String c;c = in.next();//            System.out.println(c);if (c.charAt(0) == 'A')//charAt() 方法,返回指定下标位置的字符。//如果这题考虑10 的话,这样就不行了,需要分别考虑两个字符a[i] = 1;else if (c.charAt(0) == 'J')a[i] = 11;else if (c.charAt(0) == 'Q')a[i] = 12;else if (c.charAt(0) == 'K')a[i] = 13;elsea[i] = (c.charAt(0) - '0');//c.charAt(0)检索c中的第一个字符//            System.out.println(a[i]);}ans.addElement(new Vector());ans.get(0).addElement(a[0]);//5次计算for(int i=1; i<=5; i++){ans.addElement(new Vector());for(int j = 0; j< ans.get(i - 1).size(); j++){ans.get(i).addElement(ans.get(i - 1).get(j) +a[i]);ans.get(i).addElement(ans.get(i - 1).get(j)-a[i]);ans.get(i).addElement(ans.get(i - 1).get(j)*a[i]);ans.get(i).addElement(ans.get(i - 1).get(j)/a[i]);}}//cout<

组合型枚举

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

即组合型枚举就是寻找 c_{n}^{m}问题。

组合型枚举有固定的流程,即有着固定的算法模板。

Java写法:

public class Main {static  int n;static int m;//选m个数static Vector chosen = new Vector();static  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++)System.out.print(chosen.get(i)+" ");System.out.println("");return;}calc(x + 1);chosen.addElement(x);//选calc(x + 1);chosen.remove((Object)x);//不选}public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();m = in.nextInt();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

运行限制:

1. 最大运行时间:1s
2. 最大运行内存:128M

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

代码如下:

import java.util.Scanner;
import java.util.Vector;public class Main {static  int n;static int m;//选m个数static Vector name = new Vector();static Vector ans = new Vector();static Vector chosen = new Vector();static  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.get(chosen.get(i) - 1) + " ";ans.addElement(ansTem);return;}calc(x + 1);chosen.addElement(x);calc(x + 1);chosen.remove((Object)x);}public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();m = in.nextInt();for (int i = 0; i < n; i++) {String s;s=in.next();name.addElement(s);}calc(1);for (int i = ans.size() - 1; i >= 0; i--)System.out.println(ans.get(i) );   }   
} 

 排列型枚举

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

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

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

而且排列型枚举也是有着比较成熟的模板。

  static  int n;static int[] order =new int[20];static boolean[] chosen =new boolean[20];static  void calc(int x) {if (x == n + 1) { //选够了m个数输出String ansTem = "";for (int i = 1; i <=n ; i++)System.out.println(order[i]);return;}for (int i = 1; i <= n; i++) {if (chosen[i]) continue;order[x] = i;chosen[i] =true;calc(x + 1);chosen[i] = false;order[x] = 0;}}public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();for (int i = 0; i < n; i++) {String s;s=in.next();name.addElement(s);}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

运行限制:

1. 最大运行时间:1s
2. 最大运行内存:128M

排列型枚举,但是输出元素为人名,我们可以将人名存起来,输出的时候,根据数字下标找到提前存好的人名,就是按照上一道题的方式处理即可。

代码如下: 

package com.company;import java.util.Scanner;
import java.util.Vector;public class Main {static  int n;static Vector name = new Vector();static int[] order =new int[20];static boolean[] chosen =new boolean[20];static  void calc(int x) {if (x == n + 1) { //选够了m个数输出String ansTem = "";for (int i = 1; i <=n ; i++)ansTem += name.get(order[i]-1) + " ";System.out.println(ansTem);return;}for (int i = 1; i <= n; i++) {if (chosen[i]) continue;order[x] = i;chosen[i] =true;calc(x + 1);chosen[i] = false;order[x] = 0;}}public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();for (int i = 0; i < n; i++) {String s;s=in.next();name.addElement(s);}calc(1);}
} 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章