【NOIP2015】斗地主

P2431 - 【NOIP2015】斗地主

Description

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

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

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

具体规则如下:

Input

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

接下来T组数据,每组数据n行,每行一个非负整数对aibi表示一张牌,其中ai示牌的数码,bi表示牌的花色,中间用空格隔开。
特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大
王的表示方法为02。

Output

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

Sample Input

样例输入1:

1 8

7 4

8 4

9 1

10 4

11 1

5 1

1 4

1 1

样例输入2:

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

Sample Output

样例输出1:

3

样例输出2:

6

贪心的想想,最好是先一次性出多点. 所以先打三顺子,再打双顺子,再打单顺子. 然后剩余的牌直接按照出牌的数量从大到小打. 因为能够打四带两对肯定打掉四带两对最优。

注意搜顺子的时候不一定要把顺子全部打出去. 因为可能把顺子直接打出去之后剩的都是单牌了。 然后很坑的是, 要把王炸看成一对牌,就是说王炸可以被带出去?!?!?!.

 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<iostream>
13 #include<algorithm>
14 using namespace std;
15 int sum[20],ans=100,c[10];
16 int IDA_star()
17 {
18   memset(c,0,sizeof(c));
19   int tot=0;
20   for(int i=1;i<=14;i++) c[sum[i]]++;
21   while(c[4] && c[2]>1) c[4]--,c[2]-=2,tot++;
22   while(c[4] && c[1]>1) c[4]--,c[1]-=2,tot++;
23   while(c[4] && c[2]) c[4]--,c[2]--,tot++;
24   while(c[3] && c[2]) c[3]--,c[2]--,tot++;
25   while(c[3] && c[1]) c[3]--,c[1]--,tot++;
26   return tot+c[1]+c[2]+c[3]+c[4];
27 }
28 void search(int step)
29 {
30   if(step>=ans) return;
31   for(int i=1;i<=11;i++) //三顺子
32     {
33       int j;if(sum[i]<3) continue;
34       for(j=i;sum[j]>=3 && j<=12;j++);
35       j--;
36       if(j-i+1>=2){
37     for(int j2=i+1;j2<=j;j2++){
38       for(int k=i;k<=j2;k++) sum[k]-=3;
39       search(step+1);
40       for(int k=i;k<=j2;k++) sum[k]+=3;
41     }
42       }
43     }
44   for(int i=1;i<=10;i++) //双顺子
45     {
46       int j;if(sum[i]<2) continue;
47       for(j=i;sum[j]>=2 && j<=12;j++);
48       j--;
49       if(j-i+1>=3){
50     for(int j2=i+2;j2<=j;j2++){
51       for(int k=i;k<=j2;k++) sum[k]-=2;
52       search(step+1);
53       for(int k=i;k<=j2;k++)sum[k]+=2;
54     }
55       }
56     }
57   for(int i=1;i<=8;i++) //单顺子
58     {
59       int j;if(sum[i]<1) continue;
60       for(j=i;sum[j]>=1 && j<=12;j++);
61       j--;
62       if(j-i+1>=5){
63     for(int j2=i+4;j2<=j;j2++){
64       for(int k=i;k<=j2;k++) sum[k]--;
65       search(step+1);
66       for(int k=i;k<=j2;k++) sum[k]++;
67     }
68       }
69     }
70   int cut=IDA_star();
71   if(step+cut>=ans) return;
72   else ans=step+cut;
73 }
74 int main()
75 {
76   freopen("!.in","r",stdin);
77   freopen("!.out","w",stdout);
78   int T,n;
79   scanf("%d%d",&T,&n);
80   while(T){
81     ans=100;
82     memset(sum,0,sizeof(sum));
83     T--;int x,y;
84     for(int i=1;i<=n;i++){
85       scanf("%d%d",&x,&y);
86       if(x==0) sum[14]++;
87       else sum[((x+10)%13)+1]++;
88     }
89     search(0);
90     printf("%d\n",ans);
91   }
92   return 0;
93 }

时间: 2024-11-15 00:33:29

【NOIP2015】斗地主的相关文章

NOIP2015斗地主[DFS 贪心]

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

BZOJ 4325: NOIP2015 斗地主

4325: NOIP2015 斗地主 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 684  Solved: 456[Submit][Status][Discuss] Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q

【BZOJ4325】NOIP2015 斗地主 搜索+贪心

这个东西考试的时候一眼以为状压就压炸了考试又了一下午.....最后我打出来发现后几个点10min都过不去,我大概算了一下,可能是吧.......最后一脸懵逼的我去怂了正解,我们发现只要确定了顺子就可以贪心了,所谓贪心就是在扔相同数码牌的基础上从四带二(对),四带二,三带二,三带一,开始贪心,我们的二,一一定是它本身就是这么大,因为,如果不是的话我们只是浪费了弹药却不能得到优惠,而且由于一个四可以带两个一样的单张,我们就不会出现三拆四捡的情况,我们可以把它们看成四类物品,一类是一个的,一类是两个的

NOIP2015 斗地主

Sol 暴力搜索...不用搜1,2张的情况,直接统计出来就可以了. 还有处理一下2和大王小王的位置,扔到最后面或者最前面就可以了. 搜索就搜 3+3,2+2+2,1+1+1+1+1 这三个就可以了. Code #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N = 25; int T,n,ans; int t[]={13,11,12,0,1,2,3,

noip2015斗地主

链接:https://www.luogu.org/problem/show?pid=2668 这道题正解居然是贪心... 前几天考试的时候我还想着贪心能拿几分是几分... 后来还是打了暴力... 30分... 正解:贪心,3顺子,2顺子,1顺子,4带2,4带1,三带2,三带1,4,3,2,1,特判一下双王(无论一张还是两张都ans++) 代码懒得贴了..

【uoj147】NOIP2015—斗地主

http://uoj.ac/problem/147 (题目链接) 题意 打牌... Solution 其实很简单的搜索,当年还是太年轻了.稍微想一想,顺子肯定是要先打掉的,因为顺子所包含的牌最多,所以我们可以以打出了多少张顺子为状态进行搜索,每一种状态,贪心去计算一下对于当前状态还需要打多少次才能将牌打完,不断更新答案即可. 代码: // uoj147 #include<algorithm> #include<iostream> #include<cstring> #i

bzoj4325: NOIP2015 斗地主(爆搜+模拟)

去年的我还不会打斗地主呵呵 觉得这道题挺难的..抄了一遍题解,感触挺多的= = 首先出牌的方式太多了不能每次都枚举所有的出牌方式, 于是分成两部分:1.顺子 2.带牌等其他 每次dfs都搜顺子,而且顺子不一定要全出完 所以很机智的是,方式2可以直接模拟计算出来,搜到每个状态都先用方式2计算一下最终的步数,更新答案 这样就做到每个方案都不漏了 方式二是用贪心计算的,先出四带二,四带一,然后出三带二,三带一,其他就单牌,对子等等出了 这道题很靠逻辑性,怎么出最快影响到dfs要怎么写

[BZOJ 4325][NOIP 2015] 斗地主

一道防AK好题 4325: NOIP2015 斗地主 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 820  Solved: 560[Submit][Status][Discuss] Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10&l

历年NOIP中的搜索题

什么题目都不会做于是开始做搜索题. 然而我搜索题也不会做了. 铁定没戏的蒟蒻. 1.NOIP2004 虫食算 “对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立.输入数据保证有且仅有一组解”. 大概就是给你一堆(n个)字母让你求出n进制下的一个n位数加n位数得到n位数的唯一解(允许有前导0). 千算万算没算到最大的优化是从大到小枚举数字 反正顶多26位,个位开始爆搜2333. 几个比较重要的剪枝: 当前列不可能满足立即退出. 一列三个数,知二推一. 当前答案与之前冲

7.30考试(第一发博文)

第一篇博文献给NOIP2015斗地主. 这道题为NOIP2015第一天第三题.属于爆搜类,没有任何算法,就是模拟加爆搜.由于有不同种打法,dfs分为好几层,本着先大后小便于剪枝的原则,先出顺子,再带牌,最后散着出. 首先,花色对结果无影响,其次大小王对结果是否有贡献只看是否出现其中之一,出现结果+1即可,未出现就不必管了(吐槽一下题目描述,没说四带二不算俩王,但测试点中确实不带).还有一点值得注意的是大小顺序,首先是2不算顺子,其次1比3~13都大,因此可以把大小统一减2,1.2改为12.13便