題目描述
最近,阿夸迷于德州撲克,所以她找到了很多人和她一起玩,由于人數眾多,阿夸必須更改游戲規則:
- 所有撲克牌均只看數字,不計花色,
- 每張卡的值為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個玩家的排名串列,
解題思路
1.轉換牌面:將字符陣列轉換為數字陣列
2.對每一副牌的牌面排序,分類判斷各種牌型,并計算對應的分值: (關鍵步驟)
- 將牌型由小到大劃分為等級level 1-8
- 在同一level下,利用每張牌不同的優先級計算分值
- 例如,兩對22335的分值為310000+2100+5=30205
3.按牌型、分值、姓名排序:采用結構體陣列快速排序的方法
完整代碼
#include<stdio.h>
#include<string.h>
#include <algorithm>
using namespace std;
char num[15] = "0A234567891JQK";
struct member {
char name[15];
char card1[15];
int card2[15];
int level,score,two1,two2,three,four;
}man[120000];
void convert(char str[], int x[]) {
int i, j, k;
for (i = 0, j = 0; str[i] != '\0'; i++, j++) {
for (k = 1;; k++) {
if (num[k] == str[i]) {
x[j] = k;
break;
}
}
if (x[j] == 10) {
i++;
}
}
}/*功能:轉換牌面
引數:str 為字符牌面,x 為數字牌面*/
void judge(member a,int x) {
int i;
for (i = 0; i < 5; i++) {
a.score+= a.card2[i];
}
for (i = 0; i<4; i++) {
if (a.card2[i] == a.card2[i + 1]) {
a.two1= a.card2[i];
}
if (a.card2[i] == a.card2[i + 2]) {
a.three = a.card2[i];
}
if (a.card2[i] == a.card2[i + 3]) {
a.four = a.card2[i];
}
}
for (i = 0; i < 4; i++) {
if (a.card2[i] == a.card2[i + 1]) {
a.two2 = a.card2[i];
break;
}
}
if (a.four != 0) {
a.level = 6;
a.score += a.four * 100 - 4 * a.four;
}
else if (a.three != 0 && a.two1 != a.two2) {
a.level = 5;
a.score += a.three * 100 - 3*a.three;
}
else if (a.three != 0&&a.two1==a.two2) {
a.level = 4;
a.score += a.three * 100 - 3 * a.three;
}
else if (a.two1 != a.two2) {
a.level = 3;
a.score += a.two1 * 10000 + a.two2 * 100 - 2 * a.two1 - 2 * a.two2;
}
else if (a.two1 != 0) {
a.level = 2;
a.score += a.two1 * 100 - a.two1 * 2;
}
else if (a.card2[0] == 1 && a.card2[1] == 10 && a.card2[2] == 11 && a.card2[3] == 12 && a.card2[4] == 13) {
a.level = 8;
}
else if (a.card2[1]==a.card2[0]+1&& a.card2[2] == a.card2[1] + 1 && a.card2[3] == a.card2[2] + 1 && a.card2[4] == a.card2[3] + 1 ) {
a.level = 7;
}
man[x].level = a.level;
man[x].score = a.score;
}/*分類判斷各種牌型,并計算對應的分值*/
bool cmp(member x, member y)
{
if (x.level != y.level) return x.level > y.level;
if (x.score != y.score) return x.score > y.score;
return strcmp(x.name, y.name)<0;
}/*功能:按牌型、分值、姓名非升序排序*/
int main()
{
int N, i, j = 0;
scanf("%d", &N);
for (i = 0; i < N; i++) {
scanf("%s%s", man[i].name, man[i].card1);
convert(man[i].card1, man[i].card2);/*轉換牌面*/
sort(man[i].card2, man[i].card2+5);/*對每一副牌的牌面非升序排序*/
judge(man[i],i);/*分類判斷各種牌型,并計算對應的分值*/
}
sort(man, man+N, cmp);/*按牌型、分值、姓名非升序排序*/
for (i = 0; i < N; i++) {
puts(man[i].name);
}
return 0;
}
心得
本題的關鍵在于分類判斷各種牌型,而分類的前提是“讀懂規則”,在我看來,運用紙筆或者記事本將題目規則理解透徹,應該是第一步,
復雜的規則下,本題需要的代碼量較多,對各種牌型的判斷容易出現交叉錯誤,可以嘗試對程式進行分塊化處理,分成不相關的幾個模塊,進而對各個模塊逐一突破,
在測驗資料的方面,可以考慮自己寫測驗資料,以不同等級下不同牌面為例,測驗時輸出對應的等級與分值,就可以直觀地看出問題所在,回傳該模塊進行修改,
附:
粘貼代碼到 word 的在線工具:PlanetB
使用教程->如何優雅的在 Microsoft word 中插入代碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/47152.html
標籤:C
