题目理解Clock Patience\texttt{Clock Patience}Clock Patience是一种单人纸牌游戏游戏规则如下发牌方式将一副525252张牌按照钟面的111点到121212点位置以及中心位置代表K\texttt{K}K依次发牌。第111张牌发到111点位置第222张发到222点以此类推第131313张发到中心第141414张又发到111点如此循环最终每个位置有444张牌每叠牌都是面朝下的。游戏开始取出K\texttt{K}K位置中心的最上面一张牌将其翻开成为当前牌。游戏过程根据当前牌的点数将其面朝上放在对应点数牌堆的底部然后从该牌堆顶部取出一张牌面朝下翻开成为新的当前牌。点数与位置的对应关系为A\texttt{A}A→\rightarrow→111点位置2\texttt{2}2→\rightarrow→222点位置…Q\texttt{Q}Q→\rightarrow→121212点位置K\texttt{K}K→\rightarrow→中心位置游戏结束当需要从某个牌堆取牌时该牌堆已没有面朝下的牌游戏结束。获胜条件如果所有牌都被翻开即游戏结束时所有牌堆都为空则获胜。输入格式输入包含多组数据每组数据为525252张牌分444行输入每行131313张牌牌与牌之间用空格分隔。每张牌由两个字符表示第一个字符是点数A,2,3,4,5,6,7,8,9,T,J,Q,K\texttt{A,2,3,4,5,6,7,8,9,T,J,Q,K}A,2,3,4,5,6,7,8,9,T,J,Q,K第二个字符是花色H,D,C,S\texttt{H,D,C,S}H,D,C,S。输入以单行#结束。注意输入给出的顺序是从底部到顶部即第一张牌是最后发到牌堆的最上面的牌。输出格式对于每组数据输出一行包含两个信息游戏过程中翻开的牌数两位数不足两位前补000。最后一张翻开的牌格式与输入相同。示例分析以题目给出的示例输入为例最后输出为44,KD这表示在游戏过程中翻开了444444张牌最后翻开的牌是方块K\texttt{K}KKD\texttt{KD}KD。解题思路数据结构设计我们需要模拟整个游戏过程核心数据结构包括牌的点数映射将点数字符映射为数字111到131313方便索引。这里111对应A\texttt{A}A111111对应J\texttt{J}J121212对应Q\texttt{Q}Q131313对应K\texttt{K}K。牌堆表示用131313个牌堆vector\texttt{vector}vector或list\texttt{list}list表示111到121212点位置和中心位置K\texttt{K}K。每个牌堆是一个先进后出的栈结构因为游戏过程中是从顶部取牌。当前牌记录当前翻开的牌包括其点数和花色。模拟过程详解发牌处理输入顺序是自底向上即先输入的是牌堆底部的牌。我们需要按发牌顺序重新组织牌堆。发牌顺序是第111张发到111点第222张发到222点…第131313张发到中心第141414张发到111点以此类推。因此我们可以先将输入的所有牌存入数组然后按发牌规则分配到各个牌堆。由于输入顺序是自底向上发牌时每张牌应该压入对应牌堆的顶部即最后发的牌在最上面。游戏模拟从K\texttt{K}K堆索引131313开始取出顶部牌作为当前牌。进入循环根据当前牌的点数确定目标牌堆索引。将当前牌面朝上放在目标牌堆底部本题只需记录翻开的牌不需要实际放置因为我们只关心翻牌计数和最后一张牌。从目标牌堆顶部取出一张牌作为新的当前牌。翻牌计数加111。如果目标牌堆为空游戏结束。循环结束时输出翻牌数和最后一张翻开的牌。关键细节索引对应点数A\texttt{A}A对应1112\texttt{2}2对应222…T\texttt{T}T对应101010J\texttt{J}J对应111111Q\texttt{Q}Q对应121212K\texttt{K}K对应131313。牌堆编号000对应111点111对应222点…111111对应121212点121212对应中心K\texttt{K}K。游戏终止条件当需要取牌的牌堆为空时游戏立即结束此时当前牌还没有被放入牌堆即最后翻开的牌是上一个当前牌。算法复杂度时间复杂度O(52)O(52)O(52)因为最多翻525252张牌。空间复杂度O(52)O(52)O(52)存储所有牌的信息。代码实现// Clock Patience// UVa ID: 170// Verdict: Accepted// Submission Date: 2016-02-19// UVa Run Time: 0.000s//// 版权所有C2016邱秋。metaphysis # yeah dot net#includebits/stdc.husingnamespacestd;structcard{string text;// 牌的原始表示如 KDintindex;// 牌的点数对应的索引1-13};string cardValueA23456789TJQK;// 点数映射vectorcardcards;// 存储输入的所有牌vectorvectorcardpiles;// 13个牌堆voidplay(){// 输入顺序是自底向上反转后得到自顶向下的顺序reverse(cards.begin(),cards.end());// 清空牌堆for(inti0;i12;i)piles[i].clear();// 按发牌规则分配牌到各个牌堆// 第 i 张牌0-51应该发到第 (i % 13) 个牌堆// 由于 cards 已经是自顶向下顺序直接按顺序分配即可for(inti0;i12;i)for(intj0;j3;j)piles[i].push_back(cards[j*13i]);// 每个牌堆内先分配的是底部牌后分配的是顶部牌// 但我们需要顶部牌在 vector 的前面因此反转每个牌堆for(inti0;ipiles.size();i)reverse(piles[i].begin(),piles[i].end());// 从 K 堆索引 12开始游戏intindex13;// 当前牌的点数13 表示 Kintexposed0;// 翻开的牌数string last;// 最后翻开的牌while(true){// 检查当前点数对应的牌堆是否有牌if(piles[index-1].size()){// 记录当前翻开的牌lastpiles[index-1][0].text;// 获取这张牌的点数作为下一次的目标牌堆inttemppiles[index-1][0].index;// 从牌堆顶部移除这张牌piles[index-1].erase(piles[index-1].begin());// 更新当前牌的点数indextemp;// 翻牌计数加 1exposed;}elsebreak;// 牌堆为空游戏结束}// 输出结果翻牌数占两位不足补零coutsetw(2)setfill(0)exposed,last\n;}intmain(intargc,char*argv[]){cin.tie(0);cout.sync_with_stdio(false);// 初始化 13 个牌堆for(inti1;i13;i){vectorcardpile;piles.push_back(pile);}string oneCard;intcounter0;while(cinoneCard,oneCard!#){// 将牌转换为 card 结构记录点数值cards.push_back((card){oneCard,cardValue.find(oneCard[0])1});counter;// 收集完 52 张牌后开始模拟游戏if(counter52){play();cards.clear();counter0;}}return0;}代码说明card\texttt{card}card结构存储每张牌的字符串表示和点数索引。发牌模拟先将输入的牌数组反转得到自顶向下的顺序。按发牌规则第iii张牌发到第i%13i\%13i%13个牌堆分配牌。分配完成后每个牌堆需要反转使得顶部牌在vector\texttt{vector}vector的前面。游戏模拟从K\texttt{K}K堆索引121212开始取顶部牌作为当前牌。循环中根据当前牌的点数确定下一个牌堆从该牌堆取牌。当目标牌堆为空时游戏结束。输出格式使用setw(2)\texttt{setw(2)}setw(2)和setfill(’0’)\texttt{setfill(0)}setfill(’0’)保证翻牌数为两位数。总结本题的核心是准确模拟发牌和游戏规则注意输入顺序与实际发牌顺序的关系。通过合理的数据结构如vector\texttt{vector}vector模拟栈和清晰的逻辑可以轻松完成模拟。这类题目考察的是对模拟题细节的把握能力需要仔细阅读题目描述确保每一步都符合规则。