综合实践作业一题解
P1德州扑克
分析(解题思路及流程图):
1.整体思路
该题也是一道规模较大的模拟题,对于这种实现起来比较复杂的模拟题,在认真审题明确题目的含义、了解大概方向后,可以对题目进行分块,提取出需要实现的功能,然后分模块进行实现,可以使思路变得更清晰,使实现过程变得更有条理。
因为这道题实际上是对定义的不同类型进行识别并比较大小进行排序,在审题过程中我发现,因为所包含的情况过多过于复杂,并且五张不同的牌也是以字符串的方式进行读入的,直接进行比较不太现实,所以我就想能不能通过题目所给定的排序规则乘以一定大小的数,得到统一、可比较、反应权重的间接量并且通过这个间接量来达到对不同种情况排序的目的。
2.分块处理
通过以上对于整道题的大致思路,就可以对所需要实现的功能进行分块:
(1)读入
由于所需要的属于每个玩家的信息有名字、手牌等较多不同类型的数据所以可以运用结构体进行统一管理。
(2)将手牌转化为对应面值并用数组存下
由于我需要一个反应权重的间接量,这个量肯定时整型变量,所以要将原本为字符型的手牌转化为计算起来更简便、对应面值的整型变量。
(3)计算权重
这一步时整段代码最核心的部分,首先将不同玩家手牌逐个统计,再分析情况。由于单张牌面值最大为13,所以可以用以100为公比的权数乘面值将不同的阶层或同阶层不同面值的手牌区分开,我的分类如下所示:
a.皇家同花顺:1e14
b.顺子:card51e12
c.四条:card41e10+card1
d.满堂红:card31e8+pairs[0]1e2
e.三条:card31e6+card1
f.两对:pairs[0]1e2+pairs[1]1e4+card1
g.对子:pairs[0]1e2+pairs[1]*1e4+card1
h.高牌:card1
(4)以权重和名字为参考进行进行排序
这里需要用到sort快排,并且需要自定义规则,以权重降序和名字的字典序升序排列
(5)输出
程序核心代码(或伪代码):
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct game{
char name[12];
char card[12];
int length;
int swap[5];
long long point;
};
struct cmp1{//排序规则
bool operator()(const struct game&a1,const struct game&a2)const{
if(a1.point!=a2.point) return a1.point>a2.point;
else return strcmp(a1.name,a2.name)<0;
}
};
char list[14]={'0','A','2','3','4','5','6','7','8','9','1','J','Q','K'};
int change(char a){
for(int i=0;i<14;i++){
if(a==list[i]) return i;
} //将手牌转化为它所对应的数值
}
long long count(int a[]){//通过乘不同倍数将各种情况分开得到point(权数)再排序
int form[14]={0};
for(int i=0;i<5;i++){
form[a[i]]++;
}
int card5=0,card4=0,card3=0,card1=0,pairs[2]={0};
int num=0;
for(int i=0;i<14;i++){
if(i<10){
if(form[i]==1&&form[i+1]==1&&form[i+2]==1&&form[i+3]==1&&form[i+4]==1){
card5=i+4; //找顺子
}
}
if(form[i]==5){//5张牌当作四条处理
card4=i;
card1=i;
}
if(form[i]==4) card4=i;//四条
if(form[i]==3) card3=i;//三条或满堂红
if(form[i]==2){//两对或对子
pairs[num]=i;
num++;
}
if(form[i]==1){//单牌数值累加
card1+=i;
}
}
if(form[13]==1&&form[12]==1&&form[11]==1&&form[10]==1&&form[1]==1){
return 1e14; //皇家同花顺
}
else if(card5!=0)return card5*1e12; //顺子
else if(card4!=0)return card4*1e10+card1;//四条
else if(card3!=0&&pairs[0]!=0)return card3*1e8+pairs[0]*1e2;//满堂红
else if(card3!=0&&pairs[0]==0)return card3*1e6+card1;//三条
else if(num==2){//两对
int temp;
if(pairs[0]>pairs[1]){//保证pairs[1]面值大于pairs[0]
temp=pairs[0];
pairs[0]=pairs[1];
pairs[1]=temp;
}
return pairs[0]*1e2+pairs[1]*1e4+card1;
}
else if(card3==0&&pairs[0]!=0)return pairs[0]*1e2+card1;//对子
else return card1;//高牌
}
int main(){
int n;
scanf("%d",&n);
struct game players[n];
for(int i=0;i<n;i++){
scanf("%s",players[i].name);
scanf("%s",players[i].card);
players[i].length=strlen(players[i].card);
players[i].point=0;
}
int num,sum=0;
for(int i=0;i<n;i++){//将手牌转化为对应面值用swap数组存下
for(int j=0;j<players[i].length;j++){
num=change(players[i].card[j]);
if(num!=0){
players[i].swap[sum]=num;
sum++;
}
}
sum=0;
}
for(int i=0;i<n;i++){//计算point(权数)
players[i].point=count(players[i].swap);
}
sort(players,players+n,cmp1()); //排序
for(int i=0;i<n;i++){
/*printf("%lld\n",players[i].point);*/
printf("%s",players[i].name);
if(i!=n-1) printf("\n");
}
return 0;
}
心得:
这题在实现过程中碰到的问题主要有两个:第一个是一开始采用了两次冒泡排序分别根据名字字典序升序和权重降序,虽然在思路上好像没问题,但是最后三个点超时,所以改用sort快排并自定义排序规则;第二个是在对于不同级别手牌进行分析得到权重表达式的时候错判了满堂红和三条之间的关系。然后还有就是代码的可读性较差,所以对变量进行了精简,并对变量名进行了修改。
通过该题,加深了对于较为复杂的模拟题的理解。对于规模较大的模拟题可以分布分块逐一击破,使得实现思路变得更加清晰,同时也有利于调试。