【BZOJ4325】NOIP2015 斗地主

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

题解:直接搜索。。。由于先甩龙和多带多肯定比先甩单和对强,所以先从龙判断,并且龙最好从长的龙开始判断。

然后如何甩几带几呢?这时的牌的大小已经没用了,我们可以直接用s[i]表示数量为i的牌有多少种,然后贪心的按4+2+2,4+1+1,3+2,3+1的顺序选就行了。

然而。。。对于本题来说,双王不能成对,王可以当成单,四张牌不能拆成两个对。。。

#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
int n,m,ans,cnt;
int v[20],s[20];
char str[10];
void dfs(int dep)
{
if(!cnt)
{
ans=min(ans,dep);
return ;
}
if(dep+1>=ans) return ;
int i,j;
if(v[14]&&v[15])
{
v[14]--,v[15]--,cnt-=2,dfs(dep+1),v[14]++,v[15]++,cnt+=2;
if(ans==dep+1) return ;
}
if(cnt>=6) //3龙
{
for(i=1;i<=11;i++) if(v[i]>=3&&v[i+1]>=3)
{
v[i]-=3,cnt-=3;
for(j=i+1;j<=12&&v[j]>=3;j++) v[j]-=3,cnt-=3;
for(j=j-1;j>=i+1;j--) dfs(dep+1),v[j]+=3,cnt+=3;
v[i]+=3,cnt+=3;
if(ans==dep+1) return ;
}
}
if(cnt>=6) //2龙
{
for(i=1;i<=10;i++) if(v[i]>=2&&v[i+1]>=2&&v[i+2]>=2)
{
v[i]-=2,v[i+1]-=2,cnt-=4;
for(j=i+2;j<=12&&v[j]>=2;j++) v[j]-=2,cnt-=2;
for(j=j-1;j>=i+2;j--) dfs(dep+1),v[j]+=2,cnt+=2;
v[i]+=2,v[i+1]+=2,cnt+=4;
if(ans==dep+1) return ;
}
}
if(cnt>=5) //1龙
{
for(i=1;i<=8;i++) if(v[i]&&v[i+1]&&v[i+2]&&v[i+3]&&v[i+4])
{
v[i]--,v[i+1]--,v[i+2]--,v[i+3]--,cnt-=4;
for(j=i+4;j<=12&&v[j];j++) v[j]--,cnt--;
for(j=j-1;j>=i+4;j--) dfs(dep+1),v[j]++,cnt++;
v[i]++,v[i+1]++,v[i+2]++,v[i+3]++,cnt+=4;
if(ans==dep+1) return ;
}
}
memset(s,0,sizeof(s));
for(i=1;i<=15;i++) s[v[i]]++;
while(s[4])
{
s[4]--,dep++;
if(s[2]>=2) s[2]-=2;
else if(s[1]>=2) s[1]-=2;
}
while(s[3])
{
s[3]--,dep++;
if(s[2]) s[2]--;
else if(s[1]) s[1]--;
}
dep+=s[2]+s[1]-(s[1]>=2&&v[14]&&v[15]);
ans=min(ans,dep);
}
void work()
{
ans=1<<30;
int i,a,b;
memset(v,0,sizeof(v));
for(i=1;i<=n;i++)
{
scanf("%d%d",&a,&b);
if(!a) a=b+13;
if(a==1) a=12;
else if(a==2) a=13;
else if(a<=13) a-=2;
v[a]++;
}
cnt=n;
dfs(0);
printf("%d\n",ans);
return ;
}
int main()
{
int T;
scanf("%d%d",&T,&n);
while(T--) work();
return 0;
}

【BZOJ4325】NOIP2015 斗地主 搜索+剪枝的更多相关文章

  1. 2018.11.01 bzoj4325: NOIP2015 斗地主(贪心+搜索)

    传送门 原来一直以为是一道大模拟. 没想到是一道搜索+最优性剪枝 如何搜最优呢? 我们考虑怎么最快出完. 大概是应该尽量出当前能出出去最多的吧. 于是我们选择优先出顺子. 这样做有什么好处呢? 我们会 ...

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

    这个东西考试的时候一眼以为状压就压炸了考试又了一下午.....最后我打出来发现后几个点10min都过不去,我大概算了一下,可能是吧.......最后一脸懵逼的我去怂了正解,我们发现只要确定了顺子就可以 ...

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

    去年的我还不会打斗地主呵呵 觉得这道题挺难的..抄了一遍题解,感触挺多的= = 首先出牌的方式太多了不能每次都枚举所有的出牌方式, 于是分成两部分:1.顺子 2.带牌等其他 每次dfs都搜顺子,而且顺 ...

  4. NOIP2015 斗地主(搜索+剪枝)

    4325: NOIP2015 斗地主 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 270  Solved: 192[Submit][Status] ...

  5. LOJ2422 NOIP2015 斗地主 【搜索+贪心】*

    LOJ2422 NOIP2015 斗地主 LINK 题目大意很简单,就是问你斗地主的一分手牌最少多少次出完 然后我们发现对于一种手牌状态,不考虑顺子的情况是可以贪心做掉的 然后我们直接枚举一下顺子出牌 ...

  6. NOIP2015斗地主题解 7.30考试

    问题 B: NOIP2015 斗地主 时间限制: 3 Sec  内存限制: 1024 MB 题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共 ...

  7. NOIP2015斗地主[DFS 贪心]

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

  8. BZOJ 4325: NOIP2015 斗地主

    4325: NOIP2015 斗地主 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 684  Solved: 456[Submit][Status] ...

  9. [补档][NOIP2015] 斗地主

    [NOIP2015] 斗地主 题目 传送门:http://cogs.pro/cogs/problem/problem.php?pid=2106 INPUT 第一行包含用空格隔开的2个正整数Tn,表示手 ...

随机推荐

  1. POJ 2942 Knights of the Round Table 黑白着色+点双连通分量

    题目来源:POJ 2942 Knights of the Round Table 题意:统计多个个骑士不能參加随意一场会议 每场会议必须至少三个人 排成一个圈 而且相邻的人不能有矛盾 题目给出若干个条 ...

  2. lodash toString 转换为字符串

    转换 value 为字符串. null 和 undefined 将返回空字符串.-0 将被转换为字符串"-0". _.toString(null); // => '' _.t ...

  3. Template design pattern application in android

    The template method allow separate the generic method from a detail context(class) via inheritance A ...

  4. 【Java】Java_02环境配置

    JDK是什么?JRE是什么?JDK和JRE的区别? Java Runtime Environment (JRE) 包含: Java虚拟机.库函数.运行Java应用程序和Applet所必须文件 Java ...

  5. centos mysql iptables配置

    在CentOS系统中防火墙默认是阻止3306端口的,我们要是想访问mysql数据库,我们需要这个端口,命令如下: iptables -I INPUT -p tcp --dport 3036 -j AC ...

  6. EF中多表公共字段,以及设置EntityBase使所有实体类继承自定义类

    使用EF框架访问数据库时,如果某些表具有公共字段,例如在审核流程中,对于各类申请单资料的创建人.创建时间.修改人.修改时间,这些可能多表都需要的字段,如果在每个实体中进行赋值操作显然是类似和重复的,下 ...

  7. CF Codeforces Round #256 (Div. 2) D (448D) Multiplication Table

    二分!!! AC代码例如以下: #include<iostream> #include<cstring> #include<cstdio> #define ll l ...

  8. MySQL:系列合集

    MySQL一:初识数据库 MySQL二:库操作 MySQL三:存储引擎 MySQL四:表操作 MySQL五:数据操作 MySQL六:索引原理与慢查询优化 MySQL七:数据备份 MySQL八:视图.触 ...

  9. PHP预定义常量DIRECTORY_SEPARATOR

    PHP预定义常量DIRECTORY_SEPARATOR BY 天涯 · // DIRECTORY_SEPARATOR是一个显示系统分隔符的命令,DIRECTORY_SEPARATOR是PHP的内部常量 ...

  10. 获取UUID

    UDID 设备的唯一标识符,也就是设备的序列号,在iOS2.0版本中UIDevice提供了一个获取设备唯一标识符的方法uniqueldentifier,这个方法也是为一个可以确认获取此标识符的方法.但 ...