4325:斗地主
Time Limit: 30 Sec Memory Limit: 1024 MBSubmit: 270 Solved: 192
[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,表示手牌的组数以及每组手牌的张数。
Output
共T行,每行一个整数,表示打光第T组手牌的最少次数。
Sample Input
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
Sample Output
HINT
共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方
这题看题面,很容易想到爆搜方法(然而我一开始还是想错了~~亿万只羊驼奔过),就是按他题中所说的出法,一个一个枚举,不停地枚举顺子,三带,四带,但这是非常nc的,所枚举状态之多不可想象。
所以就要枚举出牌数,这样你dfs的参量就是ans,并且更新十分方便。但需要注意的是一定不能枚举单牌,搜索复杂度很大,但是并没有什么卵用,因为你搜完了那些比较高级的出牌方式后之后,必定剩下的,就是带不走的了,所以for循环一遍统计答案即可(北岸大神骚操作),一开始我很脑残的搜单牌,于是t30,惨的一批;
代码如下:
for(int i=2;i<=15;i++) if(card[i]) now++;
ans=min(now,ans);
然后就是要处理高级的出法(顺子和带牌)
首先是带牌,思路很简单,以三带一为例。
就是搜到有三个以上牌的就再展开一层循环,枚举其他牌只要有符合条件的就接着搜出牌数++(其实就是往下搜,即dfs(now+1))。
代码如下(仅以三带一为例,其他带牌同理):
for(int i=2;i<=14;i++){
if(card[i]>=3){
card[i]-=3;
for(int j=2;j<=15;j++){
if(j==i)continue;
if(card[j]){
card[j]--;
dfs(now+1);
card[j]++;
}
}
card[i]+=3;
}
}
最后是顺子,很多人不知道怎么处理顺子,但我莫名的一看到顺子就想到一调考试T3旅馆的暴力打法,因为他都是对于一个对长度有要求的并且连续的区间进行处理,处理方法即为用一个变量记录顺子长度,满足条件就接着搜,不满足条件就把记录长度的变量赋为0(相当于从新开始),搜下一层,处理方法十分简单。
代码如下(特别注意:循环不能从2开始,一开始我因为这个一直WA35):
int len=0;
for(int i=3;i<=14;i++){//单顺
if(!card[i]) len=0;
if(card[i]){
len++;
if(len>=5){
for(int j=i;j>=i-len+1;j--) card[j]--;
dfs(now+1);
for(int j=i;j>=i-len+1;j--) card[j]++;
}
}
}
最后要说的是一个预处理的小技巧:
因为A 2 3 4 5并不能组成顺子,但10 J Q K A却能,所以把存A的数组下标置为14,这样就方便很多。
最后是学到的关于循环的知识(蛤?):
for(int j=2;j<=15&&j!=i;j++) 这种打法如果i==j会break;
但是这题你需要continue;
所以我们需要这种骚代码(此处感谢烫胸Smily一万次):
for(int j=2;j<=15;j++){
if(j==i)continue;
最后,最最重要的一点:
数组不清空,爆零两行泪!!!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int T,n; 8 int card[20]; 9 int ans=27; 10 inline bool check(){ 11 int ju=0; 12 for(int i=2;i<=14;i++){ 13 if(card[i]) ju=1; 14 } 15 return ju; 16 } 17 inline void dfs(int now){//按出牌数搜 18 if(now>=ans) return; 19 // if(!check()) ans=min(now,ans); 20 int len=0; 21 for(int i=3;i<=14;i++){//单顺 22 if(!card[i]) len=0; 23 if(card[i]){ 24 len++; 25 if(len>=5){ 26 for(int j=i;j>=i-len+1;j--) card[j]--; 27 dfs(now+1); 28 for(int j=i;j>=i-len+1;j--) card[j]++; 29 } 30 } 31 32 } 33 // if(!check()) ans=min(now,ans); 34 int lens=0; 35 for(int i=3;i<=14;i++){//双顺 36 if(card[i]<2) lens=0; 37 if(card[i]>=2){ 38 lens++; 39 if(lens>=3){ 40 for(int j=i;j>=i-lens+1;j--) card[j]-=2; 41 dfs(now+1); 42 for(int j=i;j>=i-lens+1;j--) card[j]+=2; 43 } 44 } 45 } 46 // if(!check()) ans=min(now,ans); 47 int lenc=0; 48 for(int i=3;i<=14;i++){//三顺 49 if(card[i]<3) lenc=0; 50 if(card[i]>=3){ 51 lenc++; 52 if(lenc>=2){ 53 for(int j=i;j>=i-lenc+1;j--) card[j]-=3; 54 dfs(now+1); 55 for(int j=i;j>=i-lenc+1;j--) card[j]+=3; 56 } 57 } 58 } 59 // if(!check()) ans=min(now,ans); 60 for(int i=2;i<=14;i++){ 61 if(card[i]>=3){ 62 card[i]-=3; 63 for(int j=2;j<=15;j++){ 64 if(j==i)continue; 65 if(card[j]){ 66 card[j]--; 67 dfs(now+1); 68 card[j]++; 69 } 70 } 71 card[i]+=3; 72 } 73 } 74 // if(!check()) ans=min(now,ans); 75 for(int i=2;i<=14;i++){ 76 if(card[i]>=3){ 77 card[i]-=3; 78 for(int j=2;j<=15;j++){ 79 if(j==i) continue; 80 if(card[j]>=2){ 81 card[j]-=2; 82 dfs(now+1); 83 card[j]+=2; 84 } 85 } 86 card[i]+=3; 87 } 88 } 89 // if(!check()) ans=min(now,ans); 90 for(int i=2;i<=14;i++){ 91 if(card[i]==4){ 92 card[i]-=4; 93 for(int j=2;j<=15;j++){ 94 if(j==i)continue; 95 if(card[j]){ 96 card[j]--; 97 for(int k=2;k<=15;k++){ 98 if(k==j||k==i)continue; 99 if(card[k]){ 100 card[k]--; 101 dfs(now+1); 102 card[k]++; 103 } 104 } 105 card[j]++; 106 } 107 } 108 card[i]+=4; 109 } 110 } 111 // if(!check()) ans=min(now,ans); 112 for(int i=2;i<=14;i++){ 113 if(card[i]==4){ 114 card[i]-=4; 115 for(int j=2;j<=15;j++){ 116 if(j==i) continue; 117 if(card[j]>=2){ 118 card[j]-=2; 119 for(int k=2;k<=15;k++){ 120 if(k==i||k==j)continue; 121 if(card[k]>=2){ 122 card[k]-=2; 123 dfs(now+1); 124 card[k]+=2; 125 } 126 } 127 card[j]+=2; 128 } 129 } 130 card[i]+=4; 131 } 132 } 133 for(int i=2;i<=15;i++) if(card[i]) now++; 134 ans=min(now,ans); 135 } 136 int main(){ 137 scanf("%d%d",&T,&n); 138 while(T--){ 139 ans=0x7f; 140 memset(card,0,sizeof(card)); 141 for(int i=1;i<=n;i++){ 142 int a,b; 143 scanf("%d%d",&a,&b); 144 if(a==0) a+=15; 145 if(a==1) a+=13; 146 card[a]++; 147 } 148 dfs(0); 149 printf("%d ",ans); 150 } 151 }