题目分析Hearts \texttt{Hearts}Hearts是一种纸牌游戏本题描述的是该游戏的简化版本。游戏使用一副标准的52 5252张扑克牌包含4 44种花色梅花C \texttt{C}C、方块D \texttt{D}D、红心H \texttt{H}H、黑桃S \texttt{S}S按此顺序从小到大和13 1313种点数2 22到10 1010、J \texttt{J}J、Q \texttt{Q}Q、K \texttt{K}K、A \texttt{A}A按此顺序从小到大。游戏规则要点共5 55名玩家包括庄家每人发10 1010张牌剩余2 22张牌亮出点数较大的那张牌的花色确定为将牌花色若点数相同则选择花色等级较高的作为将牌。游戏进行10 1010轮称为“墩”。每轮由一位玩家引牌其余玩家按顺时针方向跟牌。第一轮由庄家左侧的玩家引牌之后每轮由上一轮的赢家引牌。跟牌时必须优先跟同花色若无同花色则必须出将牌称为“将吃”若无将牌则垫牌出任意牌。每轮中若有人出将牌则出最大将牌者赢否则出引牌花色最大者赢。计分每轮结束后赢家收取该轮的所有牌。整局结束后统计每名玩家手中红心牌的点数之和J 11 \texttt{J}11J11Q 12 \texttt{Q}12Q12K 13 \texttt{K}13K13A 14 \texttt{A}14A14。解题思路本题要求模拟完整的游戏过程输入包含多副牌每副牌4 44行每行若干张牌输出5 55名玩家的最终得分输出顺序为庄家、庄家左侧、…、庄家右侧。牌的数据表示每张牌包含三个属性字符串形式如TS表示黑桃10 1010点数索引0~12对应2~A花色索引0~3对应C~S发牌规则发牌从庄家左侧玩家开始顺时针每人一张共发5 × 10 50 5 \times 10 505×1050张。剩余两张牌确定将牌花色。模拟每轮游戏引牌引牌者根据策略出牌 —— 从手牌中选出点数最大的牌若点数相同且其中一张是将牌则出将牌否则出花色等级较高的牌。跟牌其余玩家依次出牌策略为优先出手牌中同花色点数最大的牌若无同花色则出将牌中点数最大的牌将吃若无将牌则出手牌中点数最大的牌垫牌。确定赢家比较本轮的5 55张牌规则同题述。计分赢家收取本轮所有牌其中每张红心牌的点数累加到该玩家得分中。数据结构players5 55个向量每个向量存储一名玩家的手牌。scores5 55个整数存储玩家得分。每轮结束后赢家成为下一轮的引牌者。输入处理输入中一副牌分4 44行每行包含若干张牌每张牌由两个字符表示如TS。遇到单独一行#时终止输入。关键实现细节发牌时输入字符串需先合并再去除空白字符。剩余两张牌从输入末尾取得注意字符串索引位置前100 100100个字符对应50 5050张牌剩余4 44个字符是最后两张牌。排序比较函数需严格遵循题目中的策略。输出格式每个分数占据3 33个字符宽度右对齐输出顺序为庄家、庄家左侧、庄家对面、庄家右侧、庄家左侧的左侧即按4 → 0 → 1 → 2 → 3 4 \to 0 \to 1 \to 2 \to 34→0→1→2→3的顺序。代码实现// Hearts// UVa ID: 181// Verdict: Accepted// Submission Date: 2016-03-09// UVa Run Time: 0.000s//// 版权所有C2016邱秋。metaphysis # yeah dot net#includebits/stdc.husingnamespacestd;structcard{string text;// 牌的字符串表示如 TSintface;// 点数索引0~12 对应 2~Aintsuit;// 花色索引0~3 对应 C~S};vectorvectorcardplayers;// 5 名玩家的手牌vectorcardfollowerCards;// 当前轮所有玩家出的牌vectorintscores;// 5 名玩家的得分string faces23456789TJQKA;// 点数顺序string suitsCDHS;// 花色顺序intleader,winner,trump;// 当前引牌者、当前赢家、将牌花色card winnerCard;// 当前轮中暂时领先的牌// 判断新出的牌是否能成为当前轮的赢家voidgetWinnerCard(intindex,card followerCard){if((followerCard.suit!winnerCard.suitfollowerCard.suittrump)||(followerCard.suitwinnerCard.suitfollowerCard.facewinnerCard.face)){winnerindex;winnerCardfollowerCard;}}// 跟牌时的排序规则点数大的优先点数相同时花色大的优先boolfollowerCmp(card x,card y){return(x.face!y.face)?x.facey.face:x.suity.suit;}// 获取某位玩家的跟牌cardgetFollowerCard(intindex,card leaderCard){card followerCard;// 按跟牌策略排序手牌sort(players[index].begin(),players[index].end(),followerCmp);// 1. 优先出同花色中的最大牌boolfoundfalse;for(inti0;iplayers[index].size();i)if(players[index][i].suitleaderCard.suit){followerCardplayers[index][i];players[index].erase(players[index].begin()i);foundtrue;break;}// 2. 若无同花色则出将牌中的最大牌将吃if(foundfalse){for(inti0;iplayers[index].size();i)if(players[index][i].suittrump){followerCardplayers[index][i];players[index].erase(players[index].begin()i);foundtrue;break;}}// 3. 若既无同花色也无将牌则垫出手牌中最大牌if(foundfalse){followerCardplayers[index][0];players[index].erase(players[index].begin());}// 更新当前轮的赢家信息getWinnerCard(index,followerCard);returnfollowerCard;}// 引牌时的排序规则点数大的优先点数相同时将牌优先否则花色大的优先boolleaderCmp(card x,card y){if(x.face!y.face)returnx.facey.face;else{if(x.suittrumpy.suit!trump)returntrue;if(x.suit!trumpy.suittrump)returnfalse;returnx.suity.suit;}}// 获取引牌者的出牌cardgetLeaderCard(intindex){sort(players[index].begin(),players[index].end(),leaderCmp);card leaderCardplayers[index][0];players[index].erase(players[index].begin());returnleaderCard;}// 模拟一轮游戏voidplay(){followerCards.clear();followerCards.push_back(getLeaderCard(leader));// 引牌者出牌winnerleader;winnerCardfollowerCards.front();// 其余 4 名玩家依次跟牌for(inti1;i4;i){leader(leader1)%5;followerCards.push_back(getFollowerCard(leader,followerCards.front()));}// 赢家收取本轮所有牌统计红心牌分数for(inti0;ifollowerCards.size();i)if(followerCards[i].text[1]H)scores[winner](followerCards[i].face2);// face2 得到实际点数leaderwinner;// 下一轮由赢家引牌}intmain(intargc,char*argv[]){string line,deck;intlineNumber0;// 初始化 5 名玩家的手牌和得分for(inti1;i5;i){vectorcardcards;players.push_back(cards);scores.push_back(0);}while(getline(cin,line),line!#){lineNumber;deckline;// 合并多行输入// 每副牌共 4 行读满后处理if(lineNumber4){// 去除所有空白字符for(intideck.length()-1;i0;i--)if(isblank(deck[i]))deck.erase(deck.begin()i);// 发牌前 100 个字符对应 50 张牌每人 10 张for(inti0,j0;ideck.length()-4;i2,j){string textdeck.substr(i,2);players[j%5].push_back((card){text,(int)faces.find(text[0]),(int)suits.find(text[1])});}// 剩余两张牌第 51 张和第 52 张确定将牌花色string last1deck.substr(102,2);// 第 52 张string last2deck.substr(100,2);// 第 51 张intface1faces.find(last1[0]);intface2faces.find(last2[0]);intsuit1suits.find(last1[1]);intsuit2suits.find(last2[1]);if(face1face2)trumpsuit1suit2?suit1:suit2;// 点数相同花色等级高的为将牌elsetrumpface1face2?suit1:suit2;// 点数大的那张牌的花色为将牌// 重置得分fill(scores.begin(),scores.end(),0);// 第一轮由庄家左侧索引0引牌共进行 10 轮leader0;for(inti1;i10;i)play();// 输出结果顺序为庄家索引4、庄家左侧0、...、庄家右侧3coutsetw(3)rightscores[4];for(inti0;i3;i)coutsetw(3)rightscores[i];coutendl;// 重置准备处理下一副牌deck.clear();lineNumber0;leader0;}}return0;}样例验证输入样例TS QC 8S 8D QH 2D 3H KH 9H 2H TH KS KC 9D JH 7H JD 2S QS TD 2C 4H 5H AD 4D 5D 6D 4S 9S 5S 7S JS 8H 3D 8C 3S 4C 6S 9C AS 7C AH 6H KD JC 7D AC 5C TC QD 6C 3C #输出22 0 68 0 14与题目给出的输出一致说明模拟正确。