zoukankan      html  css  js  c++  java
  • 第6届蓝桥杯javaA组第7题,牌型种数,一道简单的题带来的思考

    题目:

    小明被劫持到X赌城,被迫与其他3人玩牌。 
    一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。 
    这时,小明脑子里突然冒出一个问题: 
    如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?

    请填写该整数,不要填写任何多余的内容或说明文字。

    拿到这道题的时候第一时间想到了解决方案:dfs。

    但是我在编写第一版的时候出现了很大的问题,导致算法复杂度为O(n^n),当然,这道题目里面的n自然就是13了。

    我的想法是:从第一张牌开始取,一直取到第13张,而每一次取牌呢,是在13种牌里面遍历,用一个数组记录每一种牌目前被取了多少,在遍历中看这个牌被取得数目是不是大于4,是的话就不取这张牌。

    然而这么做直接导致13的循环里面每一次都有13种可能,再加上排列组合,一共13^13种需要遍历。

    代码如下:

     1 import java.util.Arrays;
     2 
     3 public class Main_1 {
     4 
     5     public static void main(String[] args) {
     6         Solution s = new Solution();
     7         int[] numStates = new int[13];
     8         s.recurse(0, numStates);
     9         System.out.println(s.allPos);
    10     }
    11 }
    12 class Solution {
    13     int allPos = 0;
    14     public void recurse(int curStep, int[] numStates) {
    15         if(curStep == 13) {
    16             allPos++;
    17             System.out.println(Arrays.toString(numStates));
    18         }
    19         else {
    20             for(int i = 2; i < 15; i++) {
    21                 if(numStates[i - 2] < 4) {
    22                     numStates[i - 2]++;
    23                     recurse(curStep + 1, numStates);
    24                     numStates[i - 2]--;
    25                 }
    26             }
    27         }
    28     }
    29 }

    第一版的直接运行结果是半天没有反应,我一开始以为它陷入死循环了,结果用“System.out.println(Arrays.toString(numStates));”一看,发现一直在跑,但是过于复杂了。

    我看到这个结果以为不能用暴力法破解,然后去网上看看别人的做法,发现有人用暴力法成功了,我大致看了别人的代码之后发现我的问题可能出自暴力法之中。

    第二版我的想法是:还是递归13次,不过这次递归的是每一种牌的取得个数。也就是在13次的递归之中,每一次研究当前这种牌能取多少(具体一点就是比如说该考虑8这张牌了,那么有5种可能,从一张不拿到四张全拿),当递归次数达到13时,直接比较当前牌的总数是不是13。当然优化的方法是直接把另外一个条件也作为结束递归的标志:“目前的牌的总数大于了13,那么之后就算全部不取都无法满足条件”。算法复杂度是O(5^n),这道题目里面n = 13;

    代码如下:

     1 public class Main_2 {
     2 
     3     public static void main(String[] args) {
     4         Solution_2 s = new Solution_2();
     5         s.getResult(0, 0);
     6         System.out.println(s.num);
     7     }
     8 }
     9 
    10 class Solution_2 {
    11     public int num = 0;
    12     public void getResult(int curSum, int curStep) {
    13         if(curStep == 13 || curSum > 13) {
    14             if(curSum == 13)
    15                 num++;
    16         }
    17         else {
    18             for(int i = 0; i <= 4; i++) {
    19                 getResult(curSum + i, curStep + 1);
    20             }
    21         }
    22     }
    23 }

    这道题目给我的思考是,在用暴力法的时候直接多想几种可能,多想几种优化方案,这样可以很大程度上节约时间

  • 相关阅读:
    使用Microsoft URL Rewrite Module for IIS 7.0修改WEB.CONFIG即可实现*.HTML伪静态 无需修改应用程序映射
    我的第二个智能手机 HKC G801 严重质量问题 USB接口坏后解决办法
    JQuery的跨域方法 可跨新浪、腾讯等任意网站
    IIS7下使用MSDNURLRewriting.msi开源组件的设置
    面向对象编程,真离不开设计模式?
    jQuery 的filter(),not(),split()用法
    2008年总结
    程序中 同步和异步的经典解释 (一听就懂)
    2009年元旦前祝福 开心一下
    到底什么是SOA?
  • 原文地址:https://www.cnblogs.com/dsj2016/p/5285947.html
Copyright © 2011-2022 走看看