记录编号 207248 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 [NOIP 2015]斗地主 最终得分 100
用户昵称 GravatarSkyo 是否通过 通过
代码语言 C++ 运行时间 0.613 s
提交时间 2015-11-12 09:09:17 内存使用 1.96 MiB
显示代码纯文本
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4.  
  5. using namespace std;
  6.  
  7. const int maxn=30;
  8. const int inf=0x7fff;
  9.  
  10. int T,N;
  11. int cnt[maxn],seq[maxn];
  12.  
  13. void init()
  14. {
  15. memset(cnt,0,sizeof(cnt));
  16. memset(seq,0,sizeof(seq));
  17. }
  18.  
  19. int search()
  20. {
  21. if(N==2) {
  22. if(seq[0]==seq[1]) return 1;
  23. else return 2;
  24. }
  25. else if(N==3) {
  26. if(seq[0]==seq[1] && seq[1]==seq[2]) return 1;
  27. else if(seq[0]==seq[1] || seq[1]==seq[2]) return 2;
  28. else return 3;
  29. }
  30. else if(N==4) {
  31. if(cnt[seq[0]]==4) return 1;
  32. else if(cnt[seq[0]]==1 && cnt[seq[1]]==3) return 1;
  33. else if(cnt[seq[0]]==3 && cnt[seq[3]]==1) return 1;
  34. else if(cnt[seq[0]]==2 && cnt[seq[2]]==2) return 2;
  35. else if(seq[0]==seq[1] || seq[1]==seq[2] || seq[2]==seq[3])
  36. return 3;
  37. else return 4;
  38. }
  39. else {
  40. int ans=inf;
  41. int s1,s2,s3,t1,t2,t3;//顺子的首和尾
  42. s1=s2=s3=t1=t2=t3=3;
  43. bool finish=true;//牌是否出完
  44. //以下用14表示A,15表示2,16表示王
  45. for(int i=3;i<=16;i++) {
  46. if(cnt[i]) {
  47. finish=false;
  48. t1=i;
  49. if(t1-s1>=4 && i<15) {
  50. for(int j=s1;j<=t1-4;j++)
  51. for(int k=j+4;k<=t1;k++) {
  52. for(int l=j;l<=k;l++) cnt[l]--;//出牌
  53. ans=min(ans,search()+1);
  54. for(int l=j;l<=k;l++) cnt[l]++;//回退
  55. }//枚举顺子
  56. }
  57.  
  58. if(cnt[i]>=2) {
  59. t2=i;
  60. if(t2-s2>=2 && i<15) {
  61. for(int j=s2;j<=t2-2;j++)
  62. for(int k=j+2;k<=t2;k++) {
  63. for(int l=j;l<=k;l++) cnt[l]-=2;
  64. ans=min(ans,search()+1);
  65. for(int l=j;l<=k;l++) cnt[l]+=2;
  66. }
  67. }
  68. }
  69. else s2=i+1;
  70.  
  71. if(cnt[i]>=3) {
  72. t3=i;
  73. if(t3-s3>=1 && i<15) {
  74. for(int j=s3;j<=t3-1;j++)
  75. for(int k=j+1;k<=t3;k++) {
  76. for(int l=j;l<=k;l++) cnt[l]-=3;
  77. ans=min(ans,search()+1);
  78. for(int l=j;l<=k;l++) cnt[l]+=3;
  79. }
  80. }
  81. cnt[i]-=3;
  82. for(int j=3;j<=16;j++) {
  83. if(cnt[j] && j!=i) {
  84. cnt[j]--;
  85. ans=min(ans,search()+1);
  86. cnt[j]++;
  87. }//三带一
  88. if(cnt[j]>=2 && j<16) {
  89. cnt[j]-=2;
  90. ans=min(ans,search()+1);
  91. cnt[j]+=2;//抱歉这里刚才有个手误(但愿考场上别写错吧)
  92. }//三带二,带的两张牌不能是王(?)
  93. }
  94. cnt[i]+=3;
  95. }
  96. else s3=i+1;
  97.  
  98. if(cnt[i]==4) {
  99. cnt[i]-=4;
  100. for(int j=3;j<=16;j++)
  101. if(cnt[j]>=2) {
  102. cnt[j]-=2;
  103. ans=min(ans,search()+1);
  104. cnt[j]+=2;
  105. }//四带两张单牌,带的单牌点数相等
  106. for(int j=3;j<16;j++)
  107. for(int k=j+1;k<=16;k++) {
  108. if(cnt[j] && cnt[k]) {
  109. cnt[j]--;
  110. cnt[k]--;
  111. ans=min(ans,search()+1);
  112. cnt[j]++;
  113. cnt[k]++;
  114. }//四带二单
  115. if(cnt[j]>=2 && cnt[k]>=2 && k<16) {
  116. cnt[j]-=2;
  117. cnt[k]-=2;
  118. ans=min(ans,search()+1);
  119. cnt[j]+=2;
  120. cnt[k]+=2;
  121. }//四带两对
  122. }
  123. cnt[i]+=4;
  124. }
  125. }
  126. else s1=s2=s3=i+1;
  127. }
  128.  
  129. if(!finish) {
  130. int temp=0;
  131. for(int i=3;i<=16;i++) if(cnt[i]) temp++;
  132. ans=min(ans,temp);
  133. }//按点数处理完剩下的牌
  134. if(finish) return 0;//递归终止
  135. else return ans;
  136. }
  137.  
  138. return 233;
  139. }
  140.  
  141. int main()
  142. {
  143. freopen("landlords.in", "r", stdin);
  144. freopen("landlords.out", "w", stdout);
  145. scanf("%d%d",&T,&N);
  146. while(T--) {
  147. init();
  148. for(int i=0;i<N;i++) {
  149. int v, t;scanf("%d %d",&v,&t);
  150. if(v==0) v=16;
  151. else if(v<3) v+=13;
  152. cnt[v]++;
  153. seq[i]=v;
  154. }
  155. sort(seq,seq+N);
  156. printf("%d\n",search());
  157. }
  158. return 0;
  159. }