UVA127 纸牌游戏
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
你的任务是模拟一种叫「Accordian」的纸牌游戏,他的游戏规则如下: 一副扑克牌有52张牌,首先把纸牌一张一张由左到右排好(不能有重叠,所以共有52堆牌,每堆一张),当某一张牌与他左边那张牌或者左边的第三张牌有「Match」的时候,就把这张牌移到那张牌上面去。在这里两张牌「Match」指的是这两张牌的花色(suit)或者点数(rank)一样。当你做了一个移动之后,要察看是否还可以做其他的移动。在任何时间,只有最上面那张牌可以被移动。如果因为移动一张牌使得产生一个空格(也就是被移动的那堆牌只有一张牌),你必须把右边所有的牌堆往左移一格。如此不断的寻找可移动的牌,直到没有一张牌可以移动游戏就结束了。 在选择可以移动的牌的时候可能有些状况会发生。如果有两张牌都可以移动,你应该要移动最左边的那张牌。当一张牌可以被移动到左边一格,或左边三格的时候,你必须移动到左边三格。 Input 输入包含多组测试资料。每组测试资料两列,每列有26张牌的资料。每张牌以2个字元代表。第一个字元代表牌的点数(A=Ace, 2~9, T=10, J=Jack, Q=Queen, K=King),第二个字元代表牌的花色(C=Clubs, D =Diamonds, H=Hearts, S=Spades) 若遇到仅含#的一列代表输入结束。请参考Sample Input。 Output 对每组测试资料输出游戏结束时剩下几堆牌,以及每堆牌有多少张牌。请注意如果只有1堆牌,pile后没有加s,请参考Sample Output。 代码:非链表法 #include <algorithm> #include <iostream> #include <string> #include <vector> using namespace std; //CARD结构体,存储一张牌,Face[0]表示花色,Face[1]表示点数 struct CARD { char Face[2]; } Src; //比较两张牌是否匹配。花色或点数相同即匹配 inline bool Match(const CARD &c1, const CARD &c2) { return (c1.Face[0] == c2.Face[0] || c1.Face[1] == c2.Face[1]); } int main(void) { //主函数 typedef vector<CARD> PILE; char Pack[256]; //用于存储输入的一副牌,下面循环读取输入的数据 for (string Line; getline(cin, Line) && Line[0] != '#'; cout << endl) { strcpy(Pack, Line.c_str()); //读取并处理输入的数据 while (getline(cin, Line) && Line.empty()); //读取第2行 strcat(Pack, Line.c_str()); *remove(&Pack[0], &Pack[strlen(Pack)], ' ') = '\0'; //删除行中的空格 vector<PILE> Piles; for (int i = 0; i < 52; ++i) { //循环发出每一张牌 PILE Stack(1, ((CARD*)&Pack)[i]); Piles.push_back(Stack); //将新发的牌放在最后一叠 //j表示当前牌的位置,k表示j左边与之匹配的牌的位置 for (size_t j = Piles.size() - 1, k; j < Piles.size(); ++j) { //以下循环向左查找可以移到的最左边的位置 for (k = j, Src = Piles[j].back(); k > 0; --k) { if (k >= 3) { //先判定左边是否存在第3张 if (Match(Src, Piles[k - 3].back())) { //如果与左边第3张匹配,则将k指向这张牌 k -= 2; continue; } //虚拟移到k指向的位置,继续向左查找 } if (!Match(Src, Piles[k - 1].back())) { break; //如果左边第3张和第1张都失配,跳出循环 } } if (k != j) { //k与原位置j不相等表示可以移动 Piles[k].push_back(Piles[j].back()); //移动牌 Piles[j].pop_back(); if (Piles[j].empty()) { //如果牌叠被移空则删除之 Piles.erase(Piles.begin() + j); } j = k; //将移动牌查找的起点定为k } } } //以下按要求的格式输出结果。注意到Pile有单复数的区分 int nSize = Piles.size(); cout << nSize << " Pile" << (nSize > 1 ? "s " : " ") << "remaining:"; for (i = 0; i < nSize; cout << ' ' << (Piles[i++]).size()); } return 0; } 链表法: #include<iostream> #include<string> #include<cstring> #include<cstdio> #include<cmath> #include<vector> using namespace std; const int N=55; struct node { char face; char suit; }; vector< vector<node> > List; bool match(node a,node b) { return a.face==b.face||a.suit==b.suit; } bool test() { bool flag=false; int k,t; int s=List.size(); for(int i=s-1;i>0;i--) { if(i-3>=0&&match(List[i].back(),List[i-3].back())) { k=i; t=3; flag=true; } //根据题意,先往左边的第三个挪动 else if(i-1>=0&&match(List[i].back(),List[i-1].back())) { k=i; t=1; flag=true; } //在往左边挪动 } if(flag) { List[k-t].push_back(List[k].back()); List[k].pop_back(); if(List[k].empty()) { List.erase(List.begin()+k);//挪动后,如果该组空了,右边的都要往左边来挪动。 } return true; } return false; } //得到牌最后的位置 int main() { node p; vector<node> l; while(cin>>p.face&&p.face!='#') { cin>>p.suit; l.clear(); l.push_back(p); List.clear(); List.push_back(l); for(int i=2;i<=52;i++) { cin>>p.face>>p.suit; l.pop_back(); l.push_back(p); List.push_back(l); } while(test()); string c=List.size()>1?"s":""; cout<<List.size()<<"pile"<<c<<" remaining:"; for(i=0;i<List.size();i++) { cout<<' '<<List[i].size(); } cout<<endl; } return 0; } View Code 你的任务是模拟一种叫「Accordian」的纸牌游戏,他的游戏规则如下: 一副扑克牌有52张牌,首先把纸牌一张一张由左到右排好(不能有重叠,所以共有52堆牌,每堆一张),当某一张牌与他左边那张牌或者左边的第三张牌有「Match」的时候,就把这张牌移到那张牌上面去。在这里两张牌「Match」指的是这两张牌的花色(suit)或者点数(rank)一样。当你做了一个移动之后,要察看是否还可以做其他的移动。在任何时间,只有最上面那张牌可以被移动。如果因为移动一张牌使得产生一个空格(也就是被移动的那堆牌只有一张牌),你必须把右边所有的牌堆往左移一格。如此不断的寻找可移动的牌,直到没有一张牌可以移动游戏就结束了。 在选择可以移动的牌的时候可能有些状况会发生。如果有两张牌都可以移动,你应该要移动最左边的那张牌。当一张牌可以被移动到左边一格,或左边三格的时候,你必须移动到左边三格。 Input 输入包含多组测试资料。每组测试资料两列,每列有26张牌的资料。每张牌以2个字元代表。第一个字元代表牌的点数(A=Ace, 2~9, T=10, J=Jack, Q=Queen, K=King),第二个字元代表牌的花色(C=Clubs, D =Diamonds, H=Hearts, S=Spades) 若遇到仅含#的一列代表输入结束。请参考Sample Input。 Output 对每组测试资料输出游戏结束时剩下几堆牌,以及每堆牌有多少张牌。请注意如果只有1堆牌,pile后没有加s,请参考Sample Output。 代码:非链表法 #include <algorithm> #include <iostream> #include <string> #include <vector> using namespace std; //CARD结构体,存储一张牌,Face[0]表示花色,Face[1]表示点数 struct CARD { char Face[2]; } Src; //比较两张牌是否匹配。花色或点数相同即匹配 inline bool Match(const CARD &c1, const CARD &c2) { return (c1.Face[0] == c2.Face[0] || c1.Face[1] == c2.Face[1]); } int main(void) { //主函数 typedef vector<CARD> PILE; char Pack[256]; //用于存储输入的一副牌,下面循环读取输入的数据 for (string Line; getline(cin, Line) && Line[0] != '#'; cout << endl) { strcpy(Pack, Line.c_str()); //读取并处理输入的数据 while (getline(cin, Line) && Line.empty()); //读取第2行 strcat(Pack, Line.c_str()); *remove(&Pack[0], &Pack[strlen(Pack)], ' ') = '\0'; //删除行中的空格 vector<PILE> Piles; for (int i = 0; i < 52; ++i) { //循环发出每一张牌 PILE Stack(1, ((CARD*)&Pack)[i]); Piles.push_back(Stack); //将新发的牌放在最后一叠 //j表示当前牌的位置,k表示j左边与之匹配的牌的位置 for (size_t j = Piles.size() - 1, k; j < Piles.size(); ++j) { //以下循环向左查找可以移到的最左边的位置 for (k = j, Src = Piles[j].back(); k > 0; --k) { if (k >= 3) { //先判定左边是否存在第3张 if (Match(Src, Piles[k - 3].back())) { //如果与左边第3张匹配,则将k指向这张牌 k -= 2; continue; } //虚拟移到k指向的位置,继续向左查找 } if (!Match(Src, Piles[k - 1].back())) { break; //如果左边第3张和第1张都失配,跳出循环 } } if (k != j) { //k与原位置j不相等表示可以移动 Piles[k].push_back(Piles[j].back()); //移动牌 Piles[j].pop_back(); if (Piles[j].empty()) { //如果牌叠被移空则删除之 Piles.erase(Piles.begin() + j); } j = k; //将移动牌查找的起点定为k } } } //以下按要求的格式输出结果。注意到Pile有单复数的区分 int nSize = Piles.size(); cout << nSize << " Pile" << (nSize > 1 ? "s " : " ") << "remaining:"; for (i = 0; i < nSize; cout << ' ' << (Piles[i++]).size()); } return 0; } 链表法: #include<iostream> #include<string> #include<cstring> #include<cstdio> #include<cmath> #include<vector> using namespace std; const int N=55; struct node { char face; char suit; }; vector< vector<node> > List; bool match(node a,node b) { return a.face==b.face||a.suit==b.suit; } bool test() { bool flag=false; int k,t; int s=List.size(); for(int i=s-1;i>0;i--) { if(i-3>=0&&match(List[i].back(),List[i-3].back())) { k=i; t=3; flag=true; } //根据题意,先往左边的第三个挪动 else if(i-1>=0&&match(List[i].back(),List[i-1].back())) { k=i; t=1; flag=true; } //在往左边挪动 } if(flag) { List[k-t].push_back(List[k].back()); List[k].pop_back(); if(List[k].empty()) { List.erase(List.begin()+k);//挪动后,如果该组空了,右边的都要往左边来挪动。 } return true; } return false; } //得到牌最后的位置 int main() { node p; vector<node> l; while(cin>>p.face&&p.face!='#') { cin>>p.suit; l.clear(); l.push_back(p); List.clear(); List.push_back(l); for(int i=2;i<=52;i++) { cin>>p.face>>p.suit; l.pop_back(); l.push_back(p); List.push_back(l); } while(test()); string c=List.size()>1?"s":""; cout<<List.size()<<"pile"<<c<<" remaining:"; for(i=0;i<List.size();i++) { cout<<' '<<List[i].size(); } cout<<endl; } return 0; }