还记得那道我只用特判得了30分的“斗地主”吗?

我今天脑抽打算把它改A掉。为什么不用这大好时光去干些更有意义的事

于是我就挖了这个坑。

题解:

题目链接:P2668 斗地主

本题就是一道大搜索。按照顺序,先搜顺子、双顺子、三顺子;再搜三张牌、四张牌。

注意顺子的回溯部分,以及有四张同点数牌的时候也可以只出三张。

基本思路除了搜索之外就是贪心,优先将搜出来的多张牌一起出。

我是将双王分开存储的,防止三/四带对的时候将双王带上。

最后结束出单牌的时候,记得将对子和双王一起出。

这段代码过不了加强版数据,需要将贪心的思想换成dp。

源码有注释。

  1. //MiserWeyte is now "mzWyt"
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. int T, n, num, ul, ans;
  5. int card[20]; // 存储每种牌张数
  6. void power_sol(){ // 暴力解决n<=4
  7. if(n==2){
  8. int c1, c2;
  9. while(T--){
  10. scanf("%d%d%d%d", &c1, &ul, &c2, &ul);
  11. if(c1==c2) printf("1\n");
  12. else printf("2\n");
  13. }
  14. return;
  15. }
  16. if(n==3){
  17. int c1, c2, c3;
  18. while(T--){
  19. scanf("%d%d%d%d%d%d", &c1, &ul, &c2, &ul, &c3, &ul);
  20. if(c1==c2 && c2==c3) printf("1\n");
  21. else if(c1 == c2 && c2 != c3) printf("2\n");
  22. else if(c1 != c2 && c2 == c3) printf("2\n");
  23. else if(c1 == c3 && c2 != c3) printf("2\n");
  24. else printf("3\n");
  25. }
  26. return;
  27. }
  28. if(n==4){
  29. int c1, c2, c3, c4;
  30. while(T--){
  31. scanf("%d%d%d%d%d%d%d%d", &c1, &ul, &c2, &ul, &c3, &ul, &c4, &ul);
  32. if(c1==c2&&c2==c3&&c3==c4) printf("1\n");
  33. else if(c1==c2&&c2==c3&&c3!=c4) printf("1\n");
  34. else if(c1==c2&&c2!=c3&&c2==c4) printf("1\n");
  35. else if(c1!=c2&&c2==c3&&c3==c4) printf("1\n");
  36. else if(c1==c2&&c3==c4) printf("2\n");
  37. else if(c1==c3&&c2==c4) printf("2\n");
  38. else if(c1==c4&&c2==c3) printf("2\n");
  39. else if(c1==c2||c1==c3||c1==c4||c2==c3||c2==c4||c3==c4) printf("3\n");
  40. else printf("4\n");
  41. }
  42. return;
  43. }
  44. }
  45. void init(){
  46. memset(card, 0, sizeof(card)); // 初始化清空card数组
  47. ans = n; // 初始化ans为n(不存在比全出单张更劣的方案)
  48. }
  49. void dbg(){ // 调试,输出当前所有牌
  50. cout << endl;
  51. for(int i=0; i<=14; i++){
  52. cout << i << '\t' << card[i] << '\n';
  53. }
  54. cout << endl;
  55. }
  56. void dfs(int dep){
  57. if(dep > ans) return; // 剪枝
  58. int l; // 当前顺子长度
  59. l = 0;
  60. for(int i=3; i<=14; i++){ // 搜索单顺子
  61. if(card[i]) l ++;
  62. else l = 0;
  63. if(l >= 5){ // 长度达到顺子
  64. for(int j=i-l+1; j<=i; j++) card[j] --;
  65. // dbg();
  66. dfs(dep + 1);
  67. for(int j=i-l+1; j<=i; j++) card[j] ++;
  68. }
  69. }
  70. l = 0;
  71. for(int i=3; i<=14; i++){ // 搜索双顺子
  72. if(card[i] >= 2) l ++;
  73. else l = 0;
  74. if(l >= 3){ // 长度达到双顺子
  75. for(int j=i-l+1; j<=i; j++) card[j] -= 2;
  76. dfs(dep + 1);
  77. for(int j=i-l+1; j<=i; j++) card[j] += 2;
  78. }
  79. }
  80. l = 0;
  81. for(int i=3; i<=14; i++){ // 搜索三顺子
  82. if(card[i] >= 3) l ++;
  83. else l = 0;
  84. if(l >= 2){ // 长度达到三顺子
  85. for(int j=i-l+1; j<=i; j++) card[i] -= 3;
  86. dfs(dep + 1);
  87. for(int j=i-l+1; j<=i; j++) card[i] += 3;
  88. }
  89. }
  90. for(int i=2; i<=14; i++){ // 搜三张牌或四张牌
  91. if(card[i] >= 3){ //三带一张或一对
  92. card[i] -= 3;
  93. for(int j=0; j<=14; j++){
  94. if(!card[j] || j == i) continue;
  95. if(card[j]){
  96. card[j] --;
  97. dfs(dep + 1);
  98. card[j] ++;
  99. }
  100. if(card[j] >= 2){
  101. card[j] -= 2;
  102. dfs(dep + 1);
  103. card[j] += 2;
  104. }
  105. }
  106. card[i] += 3;
  107. if(card[i] == 4){ // 四带两张或两对
  108. card[i] -= 4;
  109. for(int j=0; j<14; j++){ //带两张
  110. if(!card[j] || j == i) continue;
  111. card[j] --;
  112. for(int k=0; k<14; k++){
  113. if(!card[k] || k == j || k == i) continue;
  114. card[k] --;
  115. dfs(dep + 1);
  116. card[k] ++;
  117. }
  118. card[j] ++;
  119. }
  120. for(int j=0; j<14; j++){ //带两对
  121. if(card[j] < 2 || j == i) continue;
  122. card[j] -= 2;
  123. for(int k=0; k<14; k++){
  124. if(card[k] < 2 || k == j || k == i) continue;
  125. card[k] -= 2;
  126. dfs(dep + 1);
  127. card[k] += 2;
  128. }
  129. card[j] += 2;
  130. }
  131. card[i] += 4;
  132. }
  133. }
  134. }
  135. for(int i=0; i<=14; i++){ // 把剩余的牌打出
  136. if(card[i]) dep ++; // 一次性打出所有相同点数的牌
  137. if(card[i] >= 3) return; // 如果有三张牌或四张牌没出,一定不是最优
  138. }
  139. if(card[0] && card[1]) dep --; // 双王可以同时打出
  140. // if(dep < ans) dbg();
  141. ans = ans < dep ? ans : dep; // ans取最小
  142. }
  143. void input(){
  144. for(int i=0; i<n; i++){
  145. scanf("%d%d", &num, &ul); // 花色并用不到(useless)
  146. if(num == 1) num = 14; // 由于A排在K后面,14存储A
  147. if(num == 0 && ul == 2) num = 1; // 双王分开存储,防止被算成一对
  148. card[num] ++;
  149. }
  150. }
  151. void work(){
  152. if(n <= 4){ // 暴力
  153. power_sol();
  154. return;
  155. }
  156. while(T--){
  157. init();
  158. input();
  159. // dbg();
  160. dfs(0);
  161. printf("%d\n", ans);
  162. }
  163. }
  164. int main(){
  165. cin >> T >> n;
  166. work();
  167. return 0;
  168. }

更新记录


记录一下,从10.31 16:32 开始改这道题。

upd 10.31 18:45:吃完饭瞅了一下之前模拟赛的时候写炸的搜索,(已经看不懂了

upd 10.31 22:16:这个月内看来是做不完了(笑 各位Happy Halloween

upd 11.1 14:57:下午翘课来机房。听取WA声一片。重写。

upd 11.3 13:19:咕咕咕(搜索思路错了 重写

upd 11.3 21:47:我过了!我过了!(作死提交了下增强数据版)(WA+TLE 80pts)(“fxxk”)

Luogu P2668 斗地主(NOIP2015)的更多相关文章

  1. 洛谷P2668 斗地主 [NOIP2015]

    题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4< ...

  2. Luogu 2540 斗地主增强版(搜索,动态规划)

    Luogu 2540 斗地主增强版(搜索,动态规划) Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游 ...

  3. 洛谷P2668 斗地主==codevs 4610 斗地主[NOIP 2015 day1 T3]

    P2668 斗地主 326通过 2.6K提交 题目提供者洛谷OnlineJudge 标签搜索/枚举NOIp提高组2015 难度提高+/省选- 提交该题 讨论 题解 记录 最新讨论 出现未知错误是说梗啊 ...

  4. 题解【洛谷P2668】[NOIP2015]斗地主

    题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的 $ A $ 到 $ K $ 加上大小王的共 $ 54 $ 张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据 ...

  5. [NOIP2015] 提高组 洛谷P2668 斗地主

    题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4< ...

  6. 洛谷P2668斗地主(搜索)noip2015

    题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4< ...

  7. 洛谷—— P2668 斗地主

    https://www.luogu.org/problem/show?pid=2668 题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54 ...

  8. 斗地主 (NOIP2015 Day1 T3)

    斗地主 张牌,因为它可以连在K后, 总体思路为 先出炸弹和四带二 再出三带一 再把对牌和单牌出完 记录并更新Answer,后枚举顺子,并继续向下搜索. 注意:弄明白题意,题目描述不太清楚....另外, ...

  9. 斗地主[NOIP2015]

    题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4< ...

随机推荐

  1. HDU 1159——Common Subsequence(DP)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=1159 题解 #include<iostream> #include<cstring> ...

  2. golang 你所不知道的 log 和 fmt

    直接点说,就是由于fmt 是线程不安全的, 如果你在多协程场景下使用fmt打印信息可能会得到乱序的结果 就是说 不按代码里的顺序打印. 下面看示例 代码示例 golang fmt 多线程 乱序: fu ...

  3. Dockerfile 构建镜像

    一.使用dockerfile构建镜像 基本结构: a.设置基础镜像 当前镜像继承于的基础镜像 FROM centos:latest  b.设置维护者信息 没有固定格式  c.设置需要添加到容器中的文件 ...

  4. 【柠檬班】jmeter 不写代码,秒秒钟提取动态列表最后一个值

    在用jmeter做接口测试时,我们经常会遇到,一个接口返回一个json串,在这个json串中,某个节点的值是一个列表,而且这个列表的长度是动态变化的.如:   获取用户列表,用户信息是个列表,类似的接 ...

  5. Python3 Linux安装(Redhat)

    Python3 Linux安装(Redhat): 下载Python-3.6.4.tgz: https://www.python.org/downloads/release/python-364/  Y ...

  6. ELK 学习笔记之 Kibana入门使用

    Kibana入门使用: 第一次导入索引: 修改展示时间,不然查不到数据: 点Discover,查阅数据: 如果要添加新的index: 点击Visualize, 创建chart: 点击Dashboard ...

  7. Mac 下安装配置MongoDB讲解

    1.访问官网地址是:MongoDB Download Center | MongoDB,一般下载server的Community 版,对于一般开发人员来说已经够用了.   2.点击“DOWNLOAD( ...

  8. CentOS 7 单机安装Redis Cluster(3主3从)

    首先,本篇要基于单实例的安装,你的机器上已经有一个Redishttps://gper.club/articles/7e7e7f7ff7g5egc4g6b 为了节省机器,我们直接把6个Redis实例安装 ...

  9. RF用例执行方法

    用例如下图: 1.执行整个项目下的所有用例 dos命令下输入robot D:\work_doc\RF (RF为下图中脚本项目Test目录的上级目录) 2.执行某个suite中的所有用例 dos命令下输 ...

  10. Android 列表(ListView、RecyclerView)不断刷新最佳实践

    本文微信公众号「AndroidTraveler」首发. 背景 在 Android 列表开发过程中,有时候我们的 Item 会有一些组件,比如倒计时.这类组件要求不断刷新,这个时候由于列表复用的机制,因 ...