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

3

HINT

共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方

片A以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张
牌(黑桃5)以及对子牌(黑桃A以及方片A)在3次内打光。
T<=10
N<=23

题解

抓取有用信息:

出牌顺序不影响出牌次数。

30分算法:

1、$T≤100$,$n≤4$;
2、先特判掉三带一的情况,然后有几种不同点数的牌,答案就是几;注意两张王可以看成是相同点数;
3、时间复杂度$O(T*n)$

100分算法:

1、$T≤10$,$n≤23$;
2、既然出牌顺序不影响,那么不妨先出对子,包括单顺、双顺、三顺。具体就是直接暴力枚举每一个顺子,然后出掉,再枚举顺子,再出掉......
3、这样可以过吗?
一个顺子至少有$5$张牌,最多出$4$组顺子,递归层数很小;
然后在一组牌内可以产生$O(K^2)$个顺子,其中$K$表示能成为顺子组成部分的牌的种数,在这里$K=12$,然后这里的复杂度就是$O(K^8)$,看起来很大,其实实测完全可以跑出来;
4、然后就可以不考虑顺子了,那么对于剩下的牌,我们就只能一个一个或者一对一对或者一带一带地出,也就是说出牌次数与牌的点数无关了;
5、那么我们可以预处理一个$dp[a][b][c][d]$,表示手牌有"$d$张单牌,$c$个对子,$b$个三张,$a$个炸弹"的时候,把牌出完的最少次数。
6、可以动态规划求解,$joker$可以拿出单独讨论。
7、时间复杂度$O(n^4+T*K^8)$。

这道题还有数据增强版,就是多考虑几个条件,把牌拆开(详见代码中的$extra$)。

 #include <set>
#include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define LL long long
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int INF = ~0u>>;
const int lenth[] = {, , , }; int n, t;
int card[], f[][][][];
int ans; int getrest(int r1, int r2, int r3, int r4, int joker){
if (joker == ) r1++,joker--;
if (joker) return Min(f[r4][r3][r2][r1+], f[r4][r3][r2][r1]+);
return f[r4][r3][r2][r1];
}
void dfs(int t){
if (t >= ans) return;
int c[] = {};
for (int i = ; i <= ; i++) c[card[i]]++;
ans = Min(ans, t+getrest(c[], c[], c[], c[], card[]));
for (int len = ; len <= ; len++)
  for (int i = ; i <= ; i++){
  int j = i;
  for (;j <= && card[j] >= len; j++){
     card[j] -= len;
    if (j-i+ >= lenth[len]) dfs(t+);
  }
  for (j--; j >= i; j--) card[j] += len;
  }
}
void pre(){
memset(f, /, sizeof(f));
f[][][][] = ;
for (int i = ; i <= n; i++)
  for (int j = ; j <= n; j++)
   for (int p = ; p <= n; p++)
     for (int q = ; q <= n; q++)
      if (i*+j*+p*+q <= n)
     {
       f[i][j][p][q] = i+j+p+q;
       if (i){
       if (p >= ) f[i][j][p][q] = Min(f[i][j][p][q], f[i-][j][p-][q]+);//四带两对
       if (q >= ) f[i][j][p][q] = Min(f[i][j][p][q], f[i-][j][p][q-]+);//四带二
       if (p) f[i][j][p][q] = Min(f[i][j][p][q], f[i][j][p-][q+]);//extra:把对子拆成一个单的
       f[i][j][p][q] = Min(f[i][j][p][q], f[i-][j][p+][q]);//extra:把炸拆成两对
       f[i][j][p][q] = Min(f[i][j][p][q], f[i-][j+][p][q+]);//extra:把炸拆成单张和三张
       f[i][j][p][q] = Min(f[i][j][p][q], f[i-][j][p][q]+);//出炸
       }
       if (j){
       if (p) f[i][j][p][q] = Min(f[i][j][p][q], f[i][j-][p-][q]+);//三带一对
       if (q) f[i][j][p][q] = Min(f[i][j][p][q], f[i][j-][p][q-]+);//三带一
       f[i][j][p][q] = Min(f[i][j][p][q], f[i][j-][p+][q+]);//extra:三拆成二+一
       f[i][j][p][q] = Min(f[i][j][p][q], f[i][j-][p][q]+);//直接出三张
       }
       if (p) f[i][j][p][q] = Min(f[i][j][p][q], f[i][j][p-][q]+);//直接出对子
      if (q) f[i][j][p][q] = Min(f[i][j][p][q], f[i][j][p][q-]+);//直接出单张
     }
} int main(){
scanf("%d%d", &t, &n);
pre();
while (t--){
   memset(card, , sizeof(card));
   int a, b;
  ans = n;
  for (int i = ; i <= n; i++){
   scanf("%d%d", &a, &b);
   if (a == ) card[]++;
   else card[a]++;
   }
   dfs();
   printf("%d\n", ans);
}
return ;
}

[NOIp 2015]斗地主的更多相关文章

  1. Luogu 2668 NOIP 2015 斗地主(搜索,动态规划)

    Luogu 2668 NOIP 2015 斗地主(搜索,动态规划) Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来 ...

  2. 基础算法(搜索):NOIP 2015 斗地主

    Description 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3& ...

  3. [BZOJ 4325][NOIP 2015] 斗地主

    一道防AK好题 4325: NOIP2015 斗地主 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 820  Solved: 560[Submit] ...

  4. [NOIP 2015] 斗地主 landlord

    想起几个月之前的 noip2015-只会瞎搞-这道题骗了 30 分.T T 题目 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的 A 到 K 加上大小王的共 54 张牌 ...

  5. noip 2015 斗地主 大爆搜!!!

    反正肯定是大模拟 但是每一个可以出的牌都搜一定不是最优的 考虑最特殊的出牌方案:顺子(单,对,三) 每一种方案再加上暴力贪心打出剩下的牌的步数 #include<cstdio> #incl ...

  6. 洛谷 P2668 & P2540 [ noip 2015 ] 斗地主 —— 搜索+贪心

    题目:https://www.luogu.org/problemnew/show/P2668   https://www.luogu.org/problemnew/show/P2540 首先,如果没有 ...

  7. 4632 NOIP[2015] 运输计划

    4632 NOIP[2015] 运输计划  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 大师 Master 题解       题目描述 Description 公元 2044 ...

  8. NOIP 2015

    Prob.1 2015 神奇的幻方 模拟就好了.(这不是noip2017的初赛题么.)代码: #include<cstdio> #include<cstring> #inclu ...

  9. [NOIP 2015]运输计划-[树上差分+二分答案]-解题报告

    [NOIP 2015]运输计划 题面: A[NOIP2015 Day2]运输计划 时间限制 : 20000 MS 空间限制 : 262144 KB 问题描述 公元 2044 年,人类进入了宇宙纪元. ...

随机推荐

  1. Beta敏捷冲刺每日报告——Day3

    1.情况简述 Beta阶段Scrum Meeting 敏捷开发起止时间 2017.11.4 00:00 -- 2017.11.5 00:00 讨论时间地点 2017.11.4 晚9:30,电话会议会议 ...

  2. 2018上C语言程序设计(高级)作业- 第2次作业

    作业要求一 提交截图: 6-7: 6-8: 6-9: 7-1: 作业要求二 题目6-7删除字符中数字字符 1.设计思路: (1)第一步:本题要求是删除字符中的数字字符,我的主要思路是通过数组遍历若遇到 ...

  3. JAVA线程概念

    一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在 ...

  4. 【iOS】OC-UTC日期字符串格式化

    NSLog(@"%@",[NSDate date]); NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init ...

  5. Syabse数据库无法启动的解决方案

    在探讨本问题之前,首先要为大家解释一下Syabse数据库本身.Syabse数据库应用和本身的架构相对而言都相对比较复杂,多数技术人员及公司对Sybase数据库底层结构和运行机制也处于并非完全了解的阶段 ...

  6. $.each遍历json数组

    1.遍历单层json数组 我们把idx和obj都打印出来看看,到底是什么东西 var json1 =[{"id":"1","tagName" ...

  7. JAVA_SE基础——43.抽象类

    高手勿喷~ 抽象类:当定义一个类时,常常需要定义一些方法来描述该类的行为特征,但有时这些方法的实现方式是无法确定的.例如定义Animal类时,shout()方法用于表示动物的叫声,但是针对不同的动物, ...

  8. Highcharts tooltip显示多条线的信息

    直接上代码吧,简单粗暴点: tooltip: { shared: true, valueSuffix: '分', formatter: function () { let s = "&quo ...

  9. Linux CentOS7.0 (01)在Vmvare Workstation上 安装配置

    一.新建虚拟机 1.创建新的虚拟机 -> 默认典型 ->选择安装介质 2.指定虚拟机名称.安装目录.磁盘容量大小 点击 "完成",创建虚拟机! 随后虚拟机将自动启动安装 ...

  10. hadoop2.6.0实践:控制台入口url列表

    hadoop web控制台页面的端口整理: 50070:hdfs文件管理 8088:ResourceManager 8042:NodeManager 19888:JobHistory(使用" ...