占卜DIY【双端队列+模拟】
题目描述
lyd学会了使用扑克DIY占卜。方法如下:一副去掉大小王的扑克共52张,打乱后均分为13堆,编号1~13,每堆4张,其中第13堆称作“生命牌”,也就是说你有4条命。这里边,4张K被称作死神。
初始状态下,所有的牌背面朝上扣下。
流程如下:
1.抽取生命牌中的最上面一张(第一张)。
2.把这张牌翻开,正面朝上,放到牌上的数字所对应编号的堆的最上边。(例如抽到2,正面朝上放到第2堆牌最上面,又比如抽到J,放到第11堆牌最上边,注意是正面朝上放)
3.从刚放了牌的那一堆最底下(最后一张)抽取一张牌,重复第2步。(例如你上次抽了2,放到了第二堆顶部,现在抽第二堆最后一张发现是8,又放到第8堆顶部…)
4.在抽牌过程中如果抽到K,则称死了一条命,就扔掉K再从第1步开始。
5.当发现四条命都死了以后,统计现在每堆牌上边正面朝上的牌的数目,只要同一数字的牌出现4张正面朝上的牌(比如4个A),则称“开了一对”,当然4个K是不算的。
6.统计一共开了多少对,开了0对称作"极凶",12对为“大凶”,3对为“凶”,45对为“小凶”,6对为“中庸”,78对“小吉”,9对为“吉”,1011为“大吉”,12为“满堂开花,极吉”。
如果还不明白,就去看样例把。。。
输入格式
一共13行,为每堆牌的具体牌是什么(不区分花色只区分数字),每堆输入的顺序为从上到下。
为了便于读入,用0代表10,那么A,J,Q,K(大写)就不用说了吧。。。
输出格式
一共开了几对。
提示
注解:第一条命死后前12堆牌变成了这个样子:
A A A 8
K 5 3 2
3 9 6 0
4 4 3 4
5 5 3 4
6 6 5 6
7 7 7 7
8 8 8 9
9 9 0 0
0 K J J
J Q A Q//抽到这里的K死掉了
J Q 2 2
第二条命由于K在生命牌中,所以直接死掉,不变。
第三条命死后前12堆牌变成了这个样子:
A A A A
2 2 2 K
3 3 3 3
4 4 4 4
5 5 5 5
6 6 6 6
7 7 7 7
8 8 8 8
9 9 9 9
0 0 0 0//抽到这里的K死掉了
J J J Q
Q Q J Q
第四条命死后前12堆牌变成了这个样子:
A A A A
2 2 2 2//抽到这里的K死掉了
3 3 3 3
4 4 4 4
5 5 5 5
6 6 6 6
7 7 7 7
8 8 8 8
9 9 9 9
0 0 0 0
J J J Q
Q Q J Q
最后发现在所有已经正面朝上的牌中,A 2 3 4 5 6 7 8 10这9对牌“开”了,(注意,第9堆牌中的最后一张虽然也是9,但是并没有被翻开!所以不能算)因此输出9,喔,出题人Lyd的运势为“吉”哦·T_T。
样例数据
输入样例 #1 输出样例 #1
//这是出题人随手写下的数据,看看他的运势如何吧…
8 5 A A
K 5 3 2
9 6 0 6
3 4 3 4
3 4 4 5
5 6 7 6
8 7 7 7
9 9 8 8
9 0 0 0
K J J J
Q A Q K
J Q 2 2
A K Q 2
9
听说两天第一题不是小学奥数就是模拟,所以联赛前刷道模拟(因为是模拟,所以代码解释较为细致)。。。
分析:数据规模极小的模拟题,随便怎么写,注意细节即可
看完题目很容易想到一种数据结构:双端队列(支持删除两端的元素),虽然你可以用for过,但是说实话写双端队列会好理解得多
这里要注意得几个问题
1.如何判断一个数字是否正面朝上?因为数字的个数可以有4个,然而同样的牌只有一张(即第一张牌,第二张牌…),所以我们存牌的信息
2.注意A是1,J是11,Q是12,K是13
#include<cstdio>
#include<iostream>
#include<cstring>
#include<deque>
using namespace std;
struct Node
{
int Num,id;//数字,编号
bool If;//If==1表示正面朝上
}xinxi[100];//xinxi[i]表示第i张牌的信息
deque<Node> q[20];//q【i】表示第i堆牌
char a;
int Life=4;//4条命
int ans,sum[20];
int main()
{
int Num;
for(int i=1;i<=13;i++)
{
for(int j=1;j<=4;j++)
{
cin>>a;
if(a=='0') Num=10;
if(a=='J') Num=11;
if(a=='Q') Num=12;
if(a=='K') Num=13;
if(a=='A') Num=1;
if(a>='2'&&a<='9') Num=a-48;
xinxi[((i-1)<<2)+j].Num=Num;
xinxi[((i-1)<<2)+j].If=0;
xinxi[((i-1)<<2)+j].id=((i-1)<<2)+j;//从上到下从左到右依次编号
q[i].push_back(xinxi[((i-1)<<2)+j]);
}
}
int x,l;
while(Life)//在没死之前
{
Num=13;//第一步
x=q[Num].front().Num,l=q[Num].front().id;
xinxi[l].If=1;//第l张牌正面朝上
q[Num].pop_front();
if(x==13)//如果第l张牌的数字是K
{
Life--;
continue;
}
q[x].push_front(xinxi[l]);
Num=x;
do
{
x=q[Num].back().Num,l=q[Num].back().id;
xinxi[l].If=1;
q[Num].pop_back();
if(x==13) break;
q[x].push_front(xinxi[l]);
Num=x;
}while(1);//以上循环请尝试自己看懂
Life--;//抽到了K,Life--
}
for(int i=1;i<=13;i++)//一共有13堆牌
{
memset(sum,0,sizeof(sum));//第i堆中,sum【j】表示数字为j的牌的个数
while(!q[i].empty())//统计每一堆牌正面朝上的数字的个数
{
if(q[i].front().If==1)
sum[q[i].front().Num]++;
q[i].pop_front();
}
for(int j=1;j<=12;j++)//除K外一种有12种牌
if(sum[j]==4) ans++;//如果一堆中有一种牌连续4张,答案加一
}
printf("%d",ans);
return 0;
}
谢谢