第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 }

這道題目給我的思考是,在用暴力法的時候直接多想幾種可能,多想幾種優化方案,這樣可以很大程度上節約時間


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM