NOIP2015 斗地主
Posted Forever_goodboy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP2015 斗地主相关的知识,希望对你有一定的参考价值。
题目描述
牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下:
输入
第一行包含用空格隔开的2个正整数T,N,表示手牌的组数以及每组手牌的张数。
接下来T组数据,每组数据N行,每行一个非负整数对Ai,Bi,表示一张牌,其中Ai表示牌的数码,Bi表示牌的花色,中间用空格隔开。特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。
输出
共T行,每行一个整数,表示打光第T组手牌的最少次数。
样例输入
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
样例输出
3
solution:
- 在第一眼看到这道题的时候,马上的感觉就是复杂。情况种类太多以至于貌似无法分类,从而导致无从下手的状态。
- 但是,我们仔细回想一下问题所在,出牌的主要特征有两种,一种是顺子,一种是重复牌。
- 对于重复牌,有两种主要的出法:第一,直接出牌,第二,带着一些其他的牌。
- 那么,我们可以考虑将重复牌和顺子分类进行处理。
- 对于每一种牌的个数预处理出来,把牌的优先级简化一下,变成1~14(注意这里大小王不能区分开!因为大小王可以组成对子,他们两个是没有优先级的区别的!)
- 深搜查找情况,在深搜中进行对顺子的枚举的处理,我们知道,对于每一个不同的顺子形成的状态,都有一个最少操作数的重复牌的操作和它相互满足。
- 即,顺子和对子的操作数加起来。正好能将所有的牌都出完。
- 深搜中枚举可行的顺子,然后在每一次深搜的时候,处理出了这些顺子之后对应的重复牌的情况,相加,即为当前操作数的总和。
- 另外,附带一句,对于重复牌的操作,一个单牌也算在重复牌操作中。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 __attribute__((optimize("O3")))int read() { 7 int s=0,f=1; 8 char ch=getchar(); 9 while(ch>‘9‘||ch<‘0‘) { 10 if(ch==‘-‘) { 11 f=-1; 12 } 13 ch=getchar(); 14 } 15 while(ch>=‘0‘&&ch<=‘9‘) { 16 s=(s<<1)+(s<<3)+(ch^48); 17 ch=getchar(); 18 } 19 return s*f; 20 } 21 int T,n,kind[25],ans,num[25]; 22 __attribute__((optimize("O3")))int get(int x) { 23 int temp=0; 24 if(x==1) { 25 temp=12; 26 } else { 27 if(x==2) { 28 temp=13; 29 } else { 30 if(x==0) { 31 temp=14; 32 } else { 33 if(x>=3&&x<=13) { 34 temp=x-2; 35 } 36 } 37 } 38 } 39 return temp; 40 } 41 __attribute__((optimize("O3")))int card() { 42 int b[6]= {0},ans=0; 43 for(int i=1; i<=15; i++) { 44 b[kind[i]]++; 45 } 46 while(b[4]&&b[2]>=2) { 47 ans++; 48 b[4]--; 49 b[2]-=2; 50 } 51 while(b[4]&&b[1]>=2) { 52 ans++; 53 b[4]--; 54 b[1]-=2; 55 } 56 while(b[3]&&b[1]>=1) { 57 ans++; 58 b[3]--; 59 b[1]--; 60 } 61 while(b[3]&&b[2]>=1) { 62 ans++; 63 b[3]--; 64 b[2]--; 65 } 66 ans+=b[1]+b[2]+b[3]+b[4]; 67 return ans; 68 } 69 __attribute__((optimize("O3")))void dfs(int step) { 70 if(step>ans) { 71 return ; 72 } 73 int x=card(); 74 ans=min(step+x,ans); 75 for(int i=1; i<=11; i++) { 76 int j; 77 for(j=i; kind[j]>=3&&j<=12; j++); 78 if(j-i<2) { 79 continue; 80 } 81 for(int k=j; k-i>=2; k--) { 82 for(int h=i; h<k; h++) { 83 kind[h]-=3; 84 } 85 dfs(step+1); 86 for(int h=i; h<k; h++) { 87 kind[h]+=3; 88 } 89 } 90 } 91 for(int i=1; i<=10; i++) { 92 int j; 93 for(j=i; kind[j]>=2&&j<=12; j++); 94 if(j-i<3) { 95 continue; 96 } 97 for(int k=j; k-i>=3; k--) { 98 for(int h=i; h<k; h++) { 99 kind[h]-=2; 100 } 101 dfs(step+1); 102 for(int h=i; h<k; h++) { 103 kind[h]+=2; 104 } 105 } 106 } 107 for(int i=1; i<=8; i++) { 108 int j; 109 for(j=i; kind[j]>=1&&j<=12; j++); 110 if(j-i<5) { 111 continue; 112 } 113 for(int k=j; k-i>=5; k--) { 114 for(int h=i; h<k; h++) { 115 kind[h]--; 116 } 117 dfs(step+1); 118 for(int h=i; h<k; h++) { 119 kind[h]++; 120 } 121 } 122 } 123 } 124 __attribute__((optimize("O3")))int main() { 125 T=read(); 126 n=read(); 127 while(T--) { 128 ans=0x7ffffff; 129 memset(kind,0,sizeof(kind)); 130 for(int i=1; i<=n; i++) { 131 int x=read(),y=read(); 132 int ji=get(x); 133 kind[ji]++; 134 //cout<<ji<<endl; 135 } 136 ans=card(); 137 dfs(0); 138 printf("%d\n",ans); 139 } 140 return 0; 141 }
以上是关于NOIP2015 斗地主的主要内容,如果未能解决你的问题,请参考以下文章