codevs2464超级麻将
题目链接http://codevs.cn/problem/2464/
题目描述 Description
很多人都知道玩麻将,当然也有人不知道,呵呵,不要紧,我在这里简要地介绍一下麻将规则:
普通麻将有砣、索、万三种类型的牌,每种牌有 1~9个数字,其中相同的牌
每个有四张,例如 1 砣~9 砣,1索~9 索,1 万~9 万各有 4 张,所以共 36*3=108张牌。胡牌时每人有 14 张牌,其中只要某人手里有若干句话(就是同种类型的牌连续三张或同种牌三张) ,另外再加上一对,即可胡牌。当然如果全是对,叫七小对,也可以胡牌。下图是连三张示例。
四万 五万 六万
四万 四万 四万
要判断某人是否胡牌,显然一个弱智的算法就行了,某中学信息学小组超级麻将迷想了想,决定将普通麻将改造成超级麻将。
所谓超级麻将没有了砣、索、万的区分,每种牌上的数字可以是 1~100,而每种数字的牌各有100 张。另外特别自由的是,玩牌的人手里想拿多少张牌都可以,好刺激哦!
刺激归刺激,但是拿多了怎么胡牌呢?
超级麻将规定只要一个人手里拿的牌是若干句话(三个连续数字的牌各一张组成一句话,三张或者四张同样数字的牌也算一句话) ,再加上一对相同的牌,就算胡了。
作为信息学竞赛选手的你,麻烦你给这位超级麻将迷编个程序,判断能否胡牌。
输入描述 Input Description
输入文件第一行一个整数 N(N<=100),表示玩了 N次超级麻将。 接下来N行,每行 100个数a1..a100,描述每次玩牌手中各种牌的数量。ai表示数字为i的牌有ai张。(0<=ai<=100)
输出描述 Output Description
输出 N行,若胡了则输出 Yes,否则输出No,注意区分 Yes,No 的大小写!
样例输入 Sample Input
3
2 4 0 0 0 0 0 …… 0(一共 98 个 0)
2 4 2 0 0 0 0 …… 0(一共 97 个 0)
2 3 2 0 0 0 0 …… 0(一共 97 个 0)
样例输出 Sample Output
Yes
Yes
No
感想:
怎么样,刚看到题目的你是不是一辆懵逼?不知所措?其实啊,我一开始也是这样(写了一个dfs,结果0分)后来在自(da)己(shen)的(de)思(bang)考(zhu)下,在做出这道题。
题解:
首先,我们要仔细读题,发现有如下这几种操作:
- 一种牌的个数-3
- 一种牌的个数-4
- 连续3种牌的个数-1
- 连续3种牌的个数-2
也许你很奇怪,不是可以再继续三种牌减下去吗(如:-4,-5)?但有没有发现三种牌-4相当于每种牌都用了一次操作2,-5相当于每种牌都用了一次操作2有用了一次操作3!以此类推,我们可以发现,一共只有如上这4种操作。
于是,我们可以先处理出一个ok数组,ok[i][j]表示i-j的差能否用操作1和操作2完成(相当于一个背包)
接下来,就是激动人心的DP啦!
f[i][j][k]代表到第i种牌为止,有j张i-1种牌,k张i种牌是否可行(即判断f[i][j][k]是否为true)
而此时,我们会发现,还要处理多出来的两张牌的情况!!!!!!!!!!!!!!这是一个棘手的问题,但我们可以在数组后面多开一维l,表示当前是否已经出现有两张的牌的情况(即l=1或l=0)。
然后,我们就可以利用ok数组和我们上面推出来的操作进行DP啦!
代码
#include <cstdio>
#include <cstring>
using namespace std;
int i,j,k,n,m,x,y,t,T,a[105],p;
bool dp[105][105][105][2],ok[105][3];
void read(int &d){
d=0;int f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){d=d*10+ch-'0';ch=getchar();}
d=d*f;
}
int main(){
memset(ok,0,sizeof ok);
for (i=0;i<=100;i++)
for (j=0;j<=2;j++)
for (k=0;k<=(i-j)/3;k++)
if ((i-j-3*k)%4==0)ok[i][j]=1;
read(T);
while (T--){
for (i=1;i<=100;i++)read(a[i]);
memset(dp,0,sizeof dp);
dp[2][a[1]][a[2]][0]=1;
for (i=2;i<=99;i++)
for (j=0;j<=a[i-1];j++)
for (k=0;k<=a[i];k++){
for (p=0;p<=1;p++){
if (ok[j][0])dp[i+1][k][a[i+1]][p]|=dp[i][j][k][p];
if (ok[j][1]&&a[i+1]>0&&k>0)dp[i+1][k-1][a[i+1]-1][p]|=dp[i][j][k][p];
if (ok[j][2]&&a[i+1]>1&&k>1)dp[i+1][k-2][a[i+1]-2][p]|=dp[i][j][k][p];
}
if (j>=2){
if (ok[j-2][0])dp[i+1][k][a[i+1]][1]|=dp[i][j][k][0];
if (ok[j-2][1]&&k>0&&a[i+1]>0)dp[i+1][k-1][a[i+1]-1][1]|=dp[i][j][k][0];
if (ok[j-2][2]&&k>1&&a[i+1]>1)dp[i+1][k-2][a[i+1]-2][1]|=dp[i][j][k][0];
}
}
bool flag=false;
for (i=0;i<=a[99];i++)if (ok[i][0])for (j=0;j<=a[100];j++)if (ok[j][0])flag|=dp[100][i][j][1];
for (i=0;i<=a[99];i++)if (ok[i][0])for (j=0;j<=a[100];j++)if (ok[j-2][0]&&j>=2)flag|=dp[100][i][j][0];
for (i=0;i<=a[99];i++)if (ok[i-2][0]&&i>=2)for (j=0;j<=a[100];j++)if (ok[j][0])flag|=dp[100][i][j][0];
if (flag)printf("Yes\n");else printf("No\n");
}
return 0;
}
codevs2464超级麻将的更多相关文章
- [ZJOI 2006]超级麻将
Description Input 第一行一个整数N(N<=100),表示玩了N次超级麻将. 接下来N行,每行100个数a1..a100,描述每次玩牌手中各种牌的数量.ai表示数字为i的牌有ai ...
- [ZJOI2006]超级麻将
题目描述 很多人都知道玩麻将,当然也有人不知道,呵呵,不要紧,我在这里简要地介绍一下麻将规则: 普通麻将有砣.索.万三种类型的牌,每种牌有1~9个数字,其中相同的牌每个有四张,例如1砣~9砣,1索~9 ...
- [ZJOI2006]超级麻将(可行性dp)
题目描述 要判断某人是否胡牌,显然一个弱智的算法就行了,某中学信息学小组超级麻将迷想了想,决定将普通麻将改造成超级麻将. 所谓超级麻将没有了砣.索.万的区分,每种牌上的数字可以是1~100,而每种数字 ...
- [ZJOI2006]超级麻将(动规)
题目描述 很多人都知道玩麻将,当然也有人不知道,呵呵,不要紧,我在这里简要地介绍一下麻将规则: 普通麻将有砣.索.万三种类型的牌,每种牌有1~9个数字,其中相同的牌每个有四张,例如1砣~9砣,1索~9 ...
- [bzoj1860 ZJOI2006] 超级麻将 (线性dp)
传送门 Description Input 第一行一个整数N(N<=100),表示玩了N次超级麻将. 接下来N行,每行100个数a1..a100,描述每次玩牌手中各种牌的数量.ai表示数字为i的 ...
- [LUOGU] P2593 [ZJOI2006]超级麻将
f[a][b][c][i]表示考虑到第i个,第i位用了b个,第i-1位用了a个,此时有将/无将(c=1/0)的情况是否可达. 转移分以下几类: 1.调一个将 f[a][b][1][i]|=f[a][b ...
- 洛谷 P2593 [ZJOI2006]超级麻将【dp】
设f[i][j][k][0/1]表示选到i时,i-1选j张,i选k张,之前选的所有牌是否选择了对子 然后分情况讨论转移即可 #include<iostream> #include<c ...
- 洛谷P2593 [ ZJOI 2006 ] 超级麻将 —— DP
题目:https://www.luogu.org/problemnew/show/P2593 DP的话,考虑到当前这一位只跟前两位有关,所以记录一下这3位的状态就行: 于是一开始记录的第 i 位,i- ...
- [Luogu2593] [ZJOI2006]超级麻将
题目地址 :https://www.luogu.org/problemnew/show/P2593. 无脑DP(虽说是抄的额) #include <iostream> #include & ...
随机推荐
- 统计学习方法c++实现之七 提升方法--AdaBoost
提升方法--AdaBoost 前言 AdaBoost是最经典的提升方法,所谓的提升方法就是一系列弱分类器(分类效果只比随机预测好一点)经过组合提升最后的预测效果.而AdaBoost提升方法是在每次训练 ...
- SICP读书笔记 2.1
SICP CONCLUSION 让我们举起杯,祝福那些将他们的思想镶嵌在重重括号之间的Lisp程序员 ! 祝我能够突破层层代码,找到住在里计算机的神灵! 目录 1. 构造过程抽象 2. 构造数据抽象 ...
- C++可继承的单例基类模板
目录 一.介绍 二.代码 三.关键处 五.参考资料 一.介绍 最近在写一个项目,其中用到好几个单例,类本身的设计不是很复杂,但是如果每个都写一遍单例又觉得有点冗余:所以查资料写了一个单例基类模板,只要 ...
- hadoop组件概念理解
一.HADOOP 二.HIVE 三.SQOOP 1.来由和作用 sqoop由一些封装好的MR程序的jar包构成,后演变成框架,但sqoop只有map任务没有reduce任务. 用于 hdfs.hive ...
- Netty源码分析第5章(ByteBuf)---->第10节: SocketChannel读取数据过程
Netty源码分析第五章: ByteBuf 第十节: SocketChannel读取数据过程 我们第三章分析过客户端接入的流程, 这一小节带大家剖析客户端发送数据, Server读取数据的流程: 首先 ...
- docker 部署 zookeeper+kafka 集群
主机三台172.16.100.61172.16.100.62172.16.100.63Docker 版本 当前最新版 # 部署zk有2种方法 ## 注意 \后不要跟空格 一 . 端口映射 172.16 ...
- 感谢Thunder
感谢Thunder团队中的每一位成员. 组长王航认真负责,是一个合格优秀的领导者与伙伴,老师布置的任务都会及时分配给每个人,对待每一项任务都认真严谨负责,了解每个成员的优势及强项. 成员李传康.宋雨. ...
- 事后分析报告(Postmortem Report)要求
在得到M1 团队成绩之后, 每个团队都需要编写一个事后分析报告,对于团队在M1阶段的工作做一个总结. 请根据下面的模板总结并发表博客: http://www.cnblogs.com/xinz/arch ...
- java 实验一
步骤 耗时h 百分比% 需求分析 0.3h 7.5 设计 2.5h 62.5 代码实现 0.5h 12.5 测试 0,2h 5 分析总结 0.5h 12.5 实验一 截图 实验二: 实验三 实现 ...
- servlet 路径问题
首先明确绝对路径与相对路径,绝对路径:相对于盘符的路径c://a.txt,相对路径格式如/web/hello.jsp.还有一个是网络路径http://www.baidu.com/...... 一般来说 ...