• 回溯法:雀魂启动!


    题目链接:雀魂启动!_牛客题霸_牛客网

    题解:

            回溯法

            1、用哈希思想构建映射表,标记已有的卡的种类和个数

            2、遍历卡池,先从卡池中抽一张卡,因为只能抽一张卡,所以一种卡只判断一次

            3、抽到卡后找雀头 -- 遍历已有卡,使用穷举法,如果手中有一种卡的数量达到两张,选其作为雀头

            4、找到雀头后找顺子和刻子 -- 再次遍历已有卡,如果手中有一种卡的数量达到三张,选其作为刻子;如果有三种卡是连号,选其作为顺子

            5、如果全部配对完后手里的卡没了,那么恭喜你和牌;如果手中还有牌剩余,那就回溯重新找

    有很多细节思路中没提到,代码中都有注释,求一个赞!!

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. vector<int> res;
    6. bool is_valid(vector<int>& cards) {
    7. //继续穷举
    8. for (int i = 1; i <= 9; i++) {
    9. //先找顺子
    10. if (cards[i] >= 3) {
    11. cards[i] -= 3;
    12. //递归,如果剩余的牌能够和牌,返回true
    13. //递归,如果剩余的牌能够和牌,返回true
    14. if (is_valid(cards)) {
    15. //回溯
    16. cards[i] += 3;
    17. return true;
    18. }
    19. //回溯
    20. cards[i] += 3;
    21. }
    22. //再找刻子
    23. if (i <= 7 && cards[i] > 0 && cards[i + 1] > 0 && cards[i + 2] > 0) {
    24. cards[i]--;
    25. cards[i + 1]--;
    26. cards[i + 2]--;
    27. //递归,如果剩余的牌能够和牌,返回true
    28. if (is_valid(cards)) {
    29. //回溯
    30. cards[i]++;
    31. cards[i + 1]++;
    32. cards[i + 2]++;
    33. return true;
    34. }
    35. //回溯
    36. cards[i]++;
    37. cards[i + 1]++;
    38. cards[i + 2]++;
    39. }
    40. }
    41. //走到这里有两种可能:
    42. // 1、有剩下的牌 -- 无法和牌返回false
    43. // 2、没剩下牌 -- 和牌返回true
    44. for (int i = 1; i <= 9; i++) {
    45. if (cards[i] > 0) {
    46. return false;
    47. }
    48. }
    49. return true;
    50. }
    51. bool head(vector<int>& cards) {
    52. //如果有两张一样的牌,先尝试作为雀头
    53. for (int i = 1; i <= 9; i++) {
    54. if (cards[i] >= 2) {
    55. cards[i] -= 2;
    56. //再用递归回溯从,剩余牌中找顺子和刻子,如果能和牌,代表这次抽取成功,打印记录
    57. if (is_valid(cards)) {
    58. //回溯 -- 这里return了就不走到70行回溯,那么找下一种组合的时候就会少两张牌,大漏洞
    59. cards[i] += 2;
    60. return true;
    61. }
    62. //回溯
    63. cards[i] += 2;
    64. }
    65. }
    66. //走到这代表没有雀头,寄
    67. return false;
    68. }
    69. void check(vector<int>& cards) {
    70. //抽一张,穷举法
    71. for (int i = 1; i <= 9; i++) {
    72. //如果有一张牌的数量小于4,代表可以抽这张牌,进行穷举
    73. if (cards[i] < 4) {
    74. //抽取
    75. cards[i]++;
    76. //继续穷举选择雀头
    77. if (head(cards)) {
    78. res.push_back(i);
    79. }
    80. //回溯
    81. cards[i]--;
    82. }
    83. }
    84. }
    85. int main() {
    86. //哈希表存放已有的牌
    87. vector<int> cards(10);
    88. //抽取13张牌
    89. for(int i=0;i<13;i++){
    90. int n;
    91. cin>>n;
    92. cards[n]++;
    93. }
    94. //回溯法检查和牌
    95. check(cards);
    96. //防止顺序不一样,排下序 -- res是全局变量,懒得传参了
    97. sort(res.begin(),res.end());
    98. for(auto v : res){
    99. cout << v <<" ";
    100. }
    101. return 0;
    102. }

  • 相关阅读:
    Springboot建筑造价师资格考试应试网站毕业设计源码260839
    计算机专业本科毕业生个人学习总结
    玩转SpringBoot:动态排除Starter配置,轻松部署
    企业网络系统工程
    ForkJoin详解
    赛博斗地主——使用大语言模型扮演Agent智能体玩牌类游戏。
    关于“非法的前向引用(illegal forward reference)”的探究
    gstream 录制音频
    what‘s the meaning of rv32imafdc
    3.初试cmake-cmake的helloworld
  • 原文地址:https://blog.csdn.net/weixin_44343938/article/details/134085299