[BZOJ 4325][NOIP 2015] 斗地主
Posted rvalue
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 4325][NOIP 2015] 斗地主相关的知识,希望对你有一定的参考价值。
一道防AK好题
4325: NOIP2015 斗地主
Time Limit: 30 Sec Memory Limit: 1024 MB
Submit: 820 Solved: 560
[Submit][Status][Discuss]Description
牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下:
Input
第一行包含用空格隔开的2个正整数T,N,表示手牌的组数以及每组手牌的张数。
接下来T组数据,每组数据N行,每行一个非负整数对Ai,Bi,表示一张牌,其中Ai表示牌的数码,Bi表示牌的花色,中间用空格隔开。特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。Output
共T行,每行一个整数,表示打光第T组手牌的最少次数。
Sample Input
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
Sample Output
3HINT
共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方
片A以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张
牌(黑桃5)以及对子牌(黑桃A以及方片A)在3次内打光。
T<=10
N<=23
港真估计只有真正的$dalao$才能在考场上思路明确地码完这题qwq
虽然实际写出来代码量倒也不算大,比某维修数列好到不知哪里去了
这种大模拟的马力出题人应该被挂起来裱(雾)
正解就是个大暴搜,$DFS$查找顺牌的同时扫描查找带牌...
查找带牌时遵循尽量出最多的牌的贪心策略即可w
需要注意的是王牌可以出现在带牌里(四个 2 带俩王2333333)但是王牌和2都不能出现在顺子里
其他的完全乱搞就行只要能保证正确性w
参考做法
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <iostream> 5 #include <algorithm> 6 7 int n; 8 int ans; 9 int sum[20]; 10 int cnt[10]; 11 12 int MakePair(); 13 void DFS(int); 14 void Initialize(); 15 int Convert(int); 16 17 int main(){ 18 int t; 19 scanf("%d%d",&t,&n); 20 while(t--){ 21 Initialize(); 22 ans=MakePair(); 23 DFS(0); 24 printf("%d\\n",ans); 25 } 26 } 27 28 void Initialize(){ 29 int x,trash; 30 memset(sum,0,sizeof(sum)); 31 for(int i=0;i<n;i++){ 32 scanf("%d%d",&x,&trash); 33 sum[Convert(x)]++; 34 } 35 } 36 37 int MakePair(){ 38 memset(cnt,0,sizeof(cnt)); 39 int ans=0; 40 for(int i=1;i<=14;i++) 41 cnt[sum[i]]++; 42 while(cnt[4]>=1&&cnt[2]>=2){ 43 cnt[4]--; 44 cnt[2]-=2; 45 ans++; 46 } 47 while(cnt[4]>=1&&cnt[1]>=2){ 48 cnt[4]--; 49 cnt[1]-=2; 50 ans++; 51 } 52 while(cnt[3]>=1&&cnt[2]>=1){ 53 cnt[3]--; 54 cnt[2]--; 55 ans++; 56 } 57 while(cnt[3]>=1&&cnt[1]>=1){ 58 cnt[3]--; 59 cnt[1]--; 60 ans++; 61 } 62 ans+=cnt[1]+cnt[2]+cnt[3]+cnt[4]; 63 return ans; 64 } 65 66 void DFS(int deep){ 67 if(deep>ans) 68 return; 69 ans=std::min(ans,deep+MakePair()); 70 for(int i=1;i<=11;i++){ 71 int tmp=i; 72 while(tmp<=12&&sum[tmp]>=3) 73 tmp++; 74 tmp--; 75 if(tmp-i+1<2) 76 continue; 77 for(int k=tmp;k-i+1>=2;k--){ 78 for(int j=i;j<=k;j++) 79 sum[j]-=3; 80 DFS(deep+1); 81 for(int j=i;j<=k;j++) 82 sum[j]+=3; 83 } 84 } 85 for(int i=1;i<=10;i++){ 86 int tmp=i; 87 while(tmp<=12&&sum[tmp]>=2) 88 tmp++; 89 tmp--; 90 if(tmp-i+1<3) 91 continue; 92 for(int k=tmp;k-i+1>=3;k--){ 93 for(int j=i;j<=k;j++) 94 sum[j]-=2; 95 DFS(deep+1); 96 for(int j=i;j<=k;j++) 97 sum[j]+=2; 98 } 99 } 100 for(int i=1;i<=8;i++){ 101 int tmp=i; 102 while(tmp<=12&&sum[tmp]>=1) 103 tmp++; 104 tmp--; 105 if(tmp-i+1<5) 106 continue; 107 for(int k=tmp;k-i+1>=5;k--){ 108 for(int j=i;j<=k;j++) 109 sum[j]--; 110 DFS(deep+1); 111 for(int j=i;j<=k;j++) 112 sum[j]++; 113 } 114 } 115 } 116 117 inline int Convert(int x){ 118 if(x==0) 119 return 14; 120 else if(x==2) 121 return 13; 122 else if(x==1) 123 return 12; 124 else 125 return x-2; 126 }
以上是关于[BZOJ 4325][NOIP 2015] 斗地主的主要内容,如果未能解决你的问题,请参考以下文章