栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

枚举法

枚举算法的思想:

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

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

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

枚举算法的一般步骤:

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

简单型枚举就是可以通过简单的 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;
 
          else
              a[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 个,这就是组合型枚举。

即组合型枚举就是寻找 问题。

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

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 个,但是关心内部的顺序。

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

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

  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);
  }
} 

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号