UOJ147 斗地主

题目描述

牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关 系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由 nn 张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。

现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。

需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下:

牌型牌型说明牌型举例
火箭 即双王(双鬼牌) ♂ ♀
炸弹 四张同点牌。 ♠A ♥A ♣A ♦A
单张牌 单张牌 ♠3
对子牌 两张码数相同的牌 ♠2 ♥2
三张牌 三张码数相同的牌 ♠3 ♥3 ♣3
三带一 三张码数相同的牌 + 一张单牌 ♠3 ♥3 ♣3 ♠4
三带二 三张码数相同的牌 + 一对牌 ♠3 ♥3 ♣3 ♠4 ♥4
单顺子 五张或更多码数连续的单牌(不包括 2 点和双王) ♠7 ♣8 ♠9 ♣10 ♣J
双顺子 三对或更多码数连续的对牌(不包括 2 点和双王) ♣3 ♥3 ♠4 ♥4 ♠5 ♥5
三顺子 二个或更多码数连续的三张牌(不能包括 2 点和双王) ♠3 ♥3 ♣3 ♠4 ♥4 ♣4 ♠5 ♦5 ♥5
四带二 四张码数相同的牌+任意两张单牌(或任意两对牌) ♠5 ♥5 ♣5 ♦5 ♣3 ♣8

输入格式

第一行包含用空格隔开的2个正整数 T,nT,n ,表示手牌的组数以及每组手牌的张数。

接下来 TT 组数据,每组数据 nn 行,每行一个非负整数对 ai,biai,bi ,表示一张牌,其中 aiai 表示牌的数码, bibi 表示牌的花色,中间用空格隔开。特别的,我们用 11 来表示数码 A, 1111表示数码 J, 1212 表示数码 Q, 1313 表示数码 K;黑桃、红心、梅花、方片分别用 1-4 来表示;小王的表示方法为 0 1 ,大王的表示方法为 0 2 。

输出格式

共 TT 行,每行一个整数,表示打光第 ii 组手牌的最少次数。

样例一

input

1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1

output

3

explanation

共有 11 组手牌,包含 88 张牌:方片 7,方片 8,黑桃 9,方片 10,黑桃 J,黑桃 5,方片 A以及黑桃 A。可以通过打单顺子(方片 7,方片 8,黑桃 9,方片 10,黑桃 J),单张牌(黑桃 5)以及对子牌(黑桃 A以及方片 A)在 33 次内打光。

样例二

input

1 17
12 3
4 3
2 3
5 4
10 2
3 3
12 2
0 1
1 3
10 1
6 2
12 1
11 3
5 2
12 4
2 2
7 2

output

6

数据规模与约定

对于不同的测试点,我们约定手牌组数 TT ,与张数 nn 的规模如下:

测试点编号TT 的规模nn 的规模测试点编号TT 的规模nn 的规模
1 100100 22 11 100100 1414
2 100100 22 12 100100 1515
3 100100 33 13 1010 1616
4 100100 33 14 1010 1717
5 100100 44 15 1010 1818
6 100100 44 16 1010 1919
7 100100 1010 17 1010 2020
8 100100 1111 18 1010 2121
9 100100 1212 19 1010 2222
10 100100 1313 20 1010 2323

数据保证:所有的手牌都是随机生成的。

 

 

正解:搜索

解题报告:

  这道题做法很多,可以状压,也可以搜索+剪枝。

  我的做法的话就是搜索+最优性剪枝,每次对于当前局面得到一个答案上界,就是能带就带,然后我只需要枚举每次打了什么顺子(三顺子、双顺子、单顺子)就可以了。

 

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 using namespace std;
14 typedef long long LL;
15 #define RG register
16 const int inf = (1<<30);
17 int n,ans;
18 int a[15],cnt[5];
19 
20 inline int getint()
21 {
22     int w=0,q=0; char c=getchar();
23     while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 
24     while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;
25 }
26 
27 inline int suan(){
28     for(int i=1;i<=4;i++) cnt[i]=0; for(int i=0;i<=13;i++) cnt[a[i]]++;
29     int tot=0;
30     while(cnt[4]>0 && cnt[2]>=2) tot++,cnt[4]--,cnt[2]-=2;//计算四带二
31     while(cnt[4]>0 && cnt[1]>=2) tot++,cnt[4]--,cnt[1]-=2;//计算四带一
32     while(cnt[3]>0 && cnt[2]>0) tot++,cnt[3]--,cnt[2]--;//计算三带二
33     while(cnt[3]>0 && cnt[1]>0) tot++,cnt[3]--,cnt[1]--;//计算三带一
34     return tot+cnt[4]+cnt[3]+cnt[2]+cnt[1];
35 } 
36 
37 inline void dfs(int step){//每次尽可能消耗的牌多
38     if(step>=ans) return ;
39     ans=min(ans,step+suan());
40     int now;
41     for(int i=2;i<=13;i++) {//三顺子
42     now=14;    for(int j=i;j<=13;j++) if(a[j]<3) { now=j; break; } 
43     if(now-i>=2) {
44         for(int k=now-i;k>=2;k--) {
45         for(int l=i;l<i+k;l++) a[l]-=3;
46         dfs(step+1);
47         for(int l=i;l<i+k;l++) a[l]+=3;
48         }
49     }
50     }
51     for(int i=2;i<=13;i++) {//双顺子
52     now=14; for(int j=i;j<=13;j++) if(a[j]<2) { now=j; break; }
53     if(now-i>=3) {
54         for(int k=now-i;k>=3;k--) {
55         for(int l=i;l<i+k;l++) a[l]-=2;
56         dfs(step+1);
57         for(int l=i;l<i+k;l++) a[l]+=2;
58         }
59     }
60     }
61     for(int i=2;i<=13;i++) {//单顺子
62     now=14; for(int j=i;j<=13;j++) if(a[j]<1) { now=j; break; }
63     if(now-i>=5) {
64         for(int k=now-i;k>=5;k--) {
65         for(int l=i;l<i+k;l++) a[l]--;
66         dfs(step+1);
67         for(int l=i;l<i+k;l++) a[l]++;
68         }
69     }
70     }
71 }
72 
73 inline void work(){
74     int T=getint(); n=getint(); int x;
75     while(T--) {
76     memset(a,0,sizeof(a));
77     for(int i=1;i<=n;i++) {
78         x=getint(); 
79         if(x==1) a[13]++;
80         else if(x==0) a[0]++;
81         else a[x-1]++;
82         x=getint();
83     }
84     ans=suan();dfs(0);
85     printf("%d\n",ans);
86     }
87 }
88 
89 int main()
90 {
91     work();
92     return 0;
93 }

 

posted @ 2016-10-08 16:23  ljh_2000  阅读(397)  评论(0编辑  收藏  举报