zoukankan      html  css  js  c++  java
  • 第一周PTA笔记 德州扑克题解

    德州扑克

    最近,阿夸迷于德州扑克。所以她找到了很多人和她一起玩。由于人数众多,阿夸必须更改游戏规则:
    所有扑克牌均只看数字,不计花色。
    每张卡的值为1、2、3、4、5、6、7、8、9、10、11、12、13 中的一种(对应A,2、3、4、5、6、7, 8、9、10,J,Q,K)
    每位玩家从一副完整的扑克牌(没有大小王)中抽出五张扑克牌,可能出现的手牌的值从低到高排列如下:
    高牌:不包含以下牌的牌。对于都是高牌的牌,按照五张牌的值的和进行从大到小排序。
    对子:手中的5张牌中有2张相同值的牌。对于都拥有对子的牌,按构成该对子的牌的值进行从大到小地排序。如果这些都相同,则按手牌中余下3张牌的值的和进行从大到小排序。
    两对:手中拥有两对不同的对子。对于都包含两对的手牌,按其最高对子的值进行从大到小排序。如果最高对子相同,则按另一个对子的值从大到小地进行排序。如果这些值相同,则按剩余牌的值从大到小地进行排序。
    三条:手中拥有3张相同值的牌。对于都包含三条的手牌按构成三条的牌的值进行从大到小地排序。如果这些值相同,则按剩余牌的值从大到小地进行排序。
    满堂红:手中拥有一个三条和一个对子。同理,先按三条大小排序,如果三条大小相同,则按对子大小进行排序。
    四条:手中拥有4张相同值的牌。对于都包含四条的手牌按构成四条的牌的值进行从大到小地排序。如果这些值相同,则按剩余牌的值从大到小地进行排序。
    顺子:手中拥有5张连续值的卡。对于都包含顺子的手牌按顺子最大的牌进行排序。
    皇家同花顺:手中拥有10到A(10、J、Q、K、A)。是最大的手牌!

    现在,阿夸已经知道了每个人的手牌,她想要知道所有人的排名列表。如果玩家的手牌大小相等,则按玩家名字的字典序输出。保证没有重复的名字。你能帮帮她吗?
    输入格式:
    第一行包含一个正整数 N (1<=N<=100000) ,表示玩家的人数。
    接下来 N 行,每行包含两个字符串:m (1<=|m|<=10 ) ,表示玩家的名字;s (1<=|s|<=10),表示玩家的手牌。
    输出格式:
    输出 N个玩家的排名列表。

    输入样例:
    3
    Alice AAA109
    Bob 678910
    Boa 678910
    
    输出样例:
    Boa
    Bob
    Alice
    

    思路:

    一开始我是将牌型通过等级,数值,名字字典序来进行逐级排序,但这样会使代码冗长而繁琐,不易检查还会导致代码运行时间超出。而后通过查阅资料和询问转换了一下思路,就是将牌型分别转化为数字,再通过qsort函数对于数字大小进行比较。

    牌型转换
    for(i=0;i<N;i++)
    		{
    			n=strlen(p[i].s);
    			for(j=0;j<n;j++)
    				{
    					if(p[i].s[j]=='1'){//遇到1时肯定是数值为10的牌
    						for(r=j+1;r<n-1;r++)
    							{
    								p[i].s[r]=p[i].s[r+1];//将之后的牌都往前进一位
    							}
    							p[i].s[n-1]='';
    							p[i].s[j]=10;
    					}
    					else if(p[i].s[j]=='J')p[i].s[j]=11;
    					else if(p[i].s[j]=='Q')p[i].s[j]=12;
    					else if(p[i].s[j]=='K')p[i].s[j]=13;
    					else if(p[i].s[j]=='A')p[i].s[j]=1;
    					else if(p[i].s[j]=='2')p[i].s[j]=2;
    					else if(p[i].s[j]=='3')p[i].s[j]=3;
    					else if(p[i].s[j]=='4')p[i].s[j]=4;
    					else if(p[i].s[j]=='5')p[i].s[j]=5;
    					else if(p[i].s[j]=='6')p[i].s[j]=6;
    					else if(p[i].s[j]=='7')p[i].s[j]=7;
    					else if(p[i].s[j]=='8')p[i].s[j]=8;
    					else if(p[i].s[j]=='9')p[i].s[j]=9;}
    

    一开始是直接将2看作字符‘2’,它的ASCII码值为50,再将其它数字以大小范围使之分布在50左右的地方,例如牌A就使它为49,但这样数值太大,到后面会不方便自己检查错误,于是直接将牌值转换为1、2、3等等。为了方便牌型判断,我对五张牌进行了非降序的排序:

    for(j=0;j<4;j++)
    				{
    					for(r=0;r<4-j;r++)
    						{
    							if(p[i].s[r]<p[i].s[r+1]){
    								t=p[i].s[r];
    								p[i].s[r]=p[i].s[r+1];
    								p[i].s[r+1]=t;
    							}//对牌进行非降序排序 (冒泡排序法)
    						}
    				}
    
    牌型判断
    if(p[i].s[0]==p[i].s[4]){
    				p[i].b-=p[i].s[2]*4;//除去四条的牌数
    				p[i].a=60+p[i].s[2]*0.01+p[i].b*0.0001; //将判断标准分级乘以小数方便比较,我将每个小等级以0.01的数量级来分开,以0.1来分应该也是可以的
    				continue; 
    			}//这是五张牌都相等的情况,判断为四条
    		   else if(p[i].s[0]==p[i].s[3]||p[i].s[1]==p[i].s[4]){
    				p[i].b-=p[i].s[2]*4;
    				p[i].a=60+p[i].s[2]*0.01+p[i].b*0.0001; 
    				continue; 
    			} //判断四条
    		   else if(p[i].s[1]==p[i].s[3]){
    				p[i].b-=p[i].s[2]*3;
    				p[i].a=40+p[i].s[2]*0.01+p[i].b*0.0001;
    				continue;
    			}//三条 
    			else if(p[i].s[0]==p[i].s[2]){
    				if(p[i].s[3]==p[i].s[4]){
    					p[i].a=50+p[i].s[0]*0.01+p[i].s[3]*0.0001;
    					continue;
    				}//满堂红
    				else{
    					p[i].b-=p[i].s[0]*3;
    					p[i].a=40+p[i].s[0]*0.01+p[i].b*0.0001;
    					continue;
    				}//三条
    			}
    			else if(p[i].s[2]==p[i].s[4]){
    				if(p[i].s[0]==p[i].s[1]){
    					p[i].a=50+p[i].s[2]*0.01+p[i].s[0]*0.0001;
    					continue;
    				}//满堂红
    				else{
    					p[i].b-=p[i].s[2]*3;
    					p[i].a=40+p[i].s[2]*0.01+p[i].b*0.0001;
    					continue;
    				}//三条
    			}
    			else if(p[i].s[0]==p[i].s[1]){
    				if(p[i].s[2]==p[i].s[3]||p[i].s[3]==p[i].s[4]){
    					p[i].b=p[i].b-p[i].s[0]*2-p[i].s[3]*2;
    					p[i].a=30+p[i].s[0]*0.01+p[i].s[3]*0.0001+p[i].b*0.000001;
    					continue;
    				}//两对
    				else{
    					p[i].b-=p[i].s[0]*2;
    					p[i].a=20+p[i].s[0]*0.01+p[i].b*0.0001;
    					continue;
    				}//一对
    			}
    			else if(p[i].s[1]==p[i].s[2]){
    				if(p[i].s[3]==p[i].s[4]){
    					p[i].a=30+p[i].s[1]*0.01+p[i].s[3]*0.0001+p[i].s[0]*0.000001;
    					continue;
    				}//两对
    				else{
    					p[i].b-=p[i].s[1]*2;
    					p[i].a=20+p[i].s[1]*0.01+p[i].b*0.0001;
    					continue;
    				}//一对
    			}
    			else if(p[i].s[2]==p[i].s[3]||p[i].s[3]==p[i].s[4]){
    				p[i].b-=p[i].s[3]*2;
    				p[i].a=20+p[i].s[3]*0.01+p[i].b*0.0001;
    				continue;
    			}//一对
    			for(j=0;j<4;j++)
    				{
    					if(p[i].s[j]-p[i].s[j+1]!=1)break;
    				}//判断顺子和同花顺
    			if(j==4){
    				p[i].a=70+p[i].s[0]*0.01;
    				continue;
    			}//顺子
    			else if(j==3&&p[i].s[4]==1&&p[i].s[0]==13){
    				p[i].a=80;
    				continue;
    			}//同花顺
    			p[i].a=10+p[i].b*0.1;//高牌
    			
    		 } 
    

    这次遇到的问题归根结底还是cmp的编写,这让我一直只过了两个点(郁闷)

    //错误代码
    int cmp(const void *p1,const void *p2)
    {
    	struct pai *c=(struct pai*)p1;
    	struct pai *d=(struct pai*)p2;
    	if(c->a!=d->a)return c->a<d->a?1:-1;
    	else return c->name>c->name?1:-1;
    
    //正确代码
    int cmp(const void *p1,const void *p2)
    {
    	struct pai *c=(struct pai*)p1;
    	struct pai *d=(struct pai*)p2;
    	if(c->a!=d->a)return c->a<d->a?1:-1;
    	else {
    		if(strcmp(c->name,d->name)>0)return 1;//用字符串函数来判断名字字典序
    		else return -1;
    	}
    }
    

    不知道错误代码的错误究竟在哪,但正确代码比较好理解又不容易出错吧,希望知道我为什么错的能帮助指出哦
    以下附上完整代码

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    struct pai{
    	char name[10];
    	char s[10];
    	double a;
    	int b;
    }p[100005];
    int main()
    {
    	int cmp(const void *p1,const void *p2);
    	int N,i,j,r,n,x;
    	char t;
    	scanf("%d",&N);
    	for(i=0;i<N;i++)
    		{
    			scanf("%s %s",p[i].name,p[i].s);
    			
    		}
    	for(i=0;i<N;i++)
    		{
    			n=strlen(p[i].s);
    			for(j=0;j<n;j++)
    				{
    					if(p[i].s[j]=='1'){
    						for(r=j+1;r<n-1;r++)
    							{
    								p[i].s[r]=p[i].s[r+1];
    							}
    							p[i].s[n-1]='';
    							p[i].s[j]=10;
    					}
    					else if(p[i].s[j]=='J')p[i].s[j]=11;
    					else if(p[i].s[j]=='Q')p[i].s[j]=12;
    					else if(p[i].s[j]=='K')p[i].s[j]=13;
    					else if(p[i].s[j]=='A')p[i].s[j]=1;
    					else if(p[i].s[j]=='2')p[i].s[j]=2;
    					else if(p[i].s[j]=='3')p[i].s[j]=3;
    					else if(p[i].s[j]=='4')p[i].s[j]=4;
    					else if(p[i].s[j]=='5')p[i].s[j]=5;
    					else if(p[i].s[j]=='6')p[i].s[j]=6;
    					else if(p[i].s[j]=='7')p[i].s[j]=7;
    					else if(p[i].s[j]=='8')p[i].s[j]=8;
    					else if(p[i].s[j]=='9')p[i].s[j]=9;}
    					p[i].b=0;
    			
    			for(j=0;j<5;j++){
    				x=p[i].s[j];
    			
    				p[i].b+=x;
    			
    			}	
    		
    			
    			for(j=0;j<4;j++)
    				{
    					for(r=0;r<4-j;r++)
    						{
    							if(p[i].s[r]<p[i].s[r+1]){
    								t=p[i].s[r];
    								p[i].s[r]=p[i].s[r+1];
    								p[i].s[r+1]=t;
    							}//对牌进行非降序排序 
    						}
    				}
    			
    			if(p[i].s[0]==p[i].s[4]){
    				p[i].b-=p[i].s[2]*4;//不是四条的牌数 
    				p[i].a=60+p[i].s[2]*0.01+p[i].b*0.0001; 
    				continue; 
    			}
    		   else if(p[i].s[0]==p[i].s[3]||p[i].s[1]==p[i].s[4]){
    				p[i].b-=p[i].s[2]*4;//不是四条的牌数 
    				p[i].a=60+p[i].s[2]*0.01+p[i].b*0.0001; 
    				continue; 
    			} 
    		   else if(p[i].s[1]==p[i].s[3]){
    				p[i].b-=p[i].s[2]*3;
    				p[i].a=40+p[i].s[2]*0.01+p[i].b*0.0001;
    				continue;
    			}//三条 
    			else if(p[i].s[0]==p[i].s[2]){
    				if(p[i].s[3]==p[i].s[4]){
    					p[i].a=50+p[i].s[0]*0.01+p[i].s[3]*0.0001;
    					continue;
    				}
    				else{
    					p[i].b-=p[i].s[0]*3;
    					p[i].a=40+p[i].s[0]*0.01+p[i].b*0.0001;
    					continue;
    				}
    			}
    			else if(p[i].s[2]==p[i].s[4]){
    				if(p[i].s[0]==p[i].s[1]){
    					p[i].a=50+p[i].s[2]*0.01+p[i].s[0]*0.0001;
    					continue;
    				}
    				else{
    					p[i].b-=p[i].s[2]*3;
    					p[i].a=40+p[i].s[2]*0.01+p[i].b*0.0001;
    					continue;
    				}
    			}
    			else if(p[i].s[0]==p[i].s[1]){
    				if(p[i].s[2]==p[i].s[3]||p[i].s[3]==p[i].s[4]){
    					p[i].b=p[i].b-p[i].s[0]*2-p[i].s[3]*2;
    					p[i].a=30+p[i].s[0]*0.01+p[i].s[3]*0.0001+p[i].b*0.000001;
    					continue;
    				}
    				else{
    					p[i].b-=p[i].s[0]*2;
    					p[i].a=20+p[i].s[0]*0.01+p[i].b*0.0001;
    					continue;
    				}
    			}
    			else if(p[i].s[1]==p[i].s[2]){
    				if(p[i].s[3]==p[i].s[4]){
    					p[i].a=30+p[i].s[1]*0.01+p[i].s[3]*0.0001+p[i].s[0]*0.000001;
    					continue;
    				}
    				else{
    					p[i].b-=p[i].s[1]*2;
    					p[i].a=20+p[i].s[1]*0.01+p[i].b*0.0001;
    					continue;
    				}
    			}
    			else if(p[i].s[2]==p[i].s[3]||p[i].s[3]==p[i].s[4]){
    				p[i].b-=p[i].s[3]*2;
    				p[i].a=20+p[i].s[3]*0.01+p[i].b*0.0001;
    				continue;
    			}
    			for(j=0;j<4;j++)
    				{
    					if(p[i].s[j]-p[i].s[j+1]!=1)break;
    				}
    			if(j==4){
    				p[i].a=70+p[i].s[0]*0.01;
    				continue;
    			}
    			else if(j==3&&p[i].s[4]==1&&p[i].s[0]==13){
    				p[i].a=80;
    				continue;
    			}
    			p[i].a=10+p[i].b*0.1;
    			
    		 } 
    	
    	qsort(p,N,sizeof(struct pai),cmp);
    
    	for(i=0;i<N;i++)
    		{
    			printf("%s
    ",p[i].name);
    		}
    	return 0;
    }
    int cmp(const void *p1,const void *p2)
    {
    	struct pai *c=(struct pai*)p1;
    	struct pai *d=(struct pai*)p2;
    	if(c->a!=d->a)return c->a<d->a?1:-1;
    	else {
    		if(strcmp(c->name,d->name)>0)return 1;
    		else return -1;
    	}
    }
    

    写此题解为了纪念我被这道题折磨的这几天(土拨鼠尖叫)啊啊啊啊啊啊啊啊

  • 相关阅读:
    使用Bootstrap模态框实现增删改查功能
    表中多个按钮进行操作不需要跳转页面的实现
    在调试javascript的时候,要常使用alert()
    Request.UrlReferrer 实现页面刷新
    确认框的使用。弹出一个确认框,Ajax提交一个请求,刷新页面。
    条件构造器queryWrapper和updateWrapper
    接口调用:从第三方接口获取数据
    Dictionary的用法
    数组和List之间的转换
    调用存储过程
  • 原文地址:https://www.cnblogs.com/ponynice/p/12391724.html
Copyright © 2011-2022 走看看