/* 题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=63 这题也是比较考思维,好像没什么特别的技巧和知识点,但是自己想的时候,怎么也想不到用 vector< vector<card> > 处理的这种方式... 可能STL学的还不够熟练吧... 参考了别人的题解和思路,别人的思路真是太巧妙了,引用一句评价: “每次只输入一张牌,马上向前查看是否能匹配,而不是一副牌都分配好后再来插入和删除,效率高,实现效果好。” 总结一下:值得重做的题,可以极大加深对STL的理解。 而且,如果一开始不看题解,而是先自己想该怎么实现,很久没有想明白以后,再去看题解,更能发现,这个博主的思路真的非常非常巧妙,让人想要拊掌称叹 */
/*
参考借鉴思路于:
http://blog.csdn.net/bb2b2bbb/article/details/26484267
*/
#include <iostream>
#include <vector>
#define rep(i, j, n) for (int i = j; i < n; i++)
using namespace std;
struct card
{
char number, color;
card(char n = ' ', char c = ' '):number(n), color(c)
{
}
};
vector<vector<card> > vec;
int deal(card c, int size)
{ //该函数返回牌插入的位置,因为牌的规则包含各种 match 和 移动 的情况的处理
int tp; //temp
while (size > 0) //开始判断能否 match 、能否移动,可左移一格也可左移格时,移动3格,所以先判断3格的情况
{
if (size >= 3)
{
tp = (int)vec[size - 3].size() - 1; //最顶端的牌才能参与 match 或者参与移动,tp是最顶端的牌的下标
card& c0 = vec[size - 3][tp];
if ( c0.number == c.number || c0.color == c.color )
{
size -= 3;
continue;
}
}
if (size >= 1)
{
tp = (int)vec[size - 1].size() - 1; //最顶端的牌才能参与 match 或者参与移动,tp是最顶端的牌的下标
card& c0 = vec[size - 1][tp];
if ( c0.number == c.number || c0.color == c.color )
{
size -= 1;
continue;
}
}
break; //如果有移动,则可不断继续判断,是否仍满足移动的条件,直到不能移动为止,不能移动时,跳出循环
}
return size; //返回该牌最终放置的位置
}
void solve()
{
char input[3];
while (cin >> input && input[0] != '#')
{
int num = 52;
while (num--)
{
card c(input[0], input[1]);
int pos = deal(c, (int)vec.size());
if (pos == (int)vec.size()) //卡片没有移动,直接插入
{
vector<card> v(1, c);
vec.push_back(v);
}
else //卡片能移动,pos是卡片最终放置的位置
{
vec[pos].push_back(c);
Again: rep( i, pos + 1, (int)vec.size() )
//每次一旦有卡片插入,则跳到卡片插入位置之后,找其后还有没有可插入的卡片;所以相当于是进入了一个全新的循环,和原来的循环完全不同了。这点用标号来实现最为简洁,所以尽管不建议用goto,但在这里,我想不到比goto更好的代替方式了
{
card d = vec[i][(int)vec[i].size() - 1];
int loc = deal(d, i); //loc::location,这里的处理挺有意思,把已经遍历过的牌堆的后一个牌堆,这个牌堆上的最顶部的牌,当作是要插入已经排好的那些牌堆中,看看这张牌能不能移动
if ( loc != i )
{
vec[loc].push_back(d); //把这种牌插入该移动到的位置
vec[i].pop_back(); //把这张牌从原来的堆顶移除
if (vec[i].empty())
vec.erase(vec.begin() + i); //如果删完以后,牌堆空了,整个牌堆移除
pos = loc; //更新下已经拍好的牌堆的数目,使得从已经排好的牌堆的后面,再来找有没有可以移动的牌堆
goto Again;
}
}
}
if (!num) break; //这组的52张牌全部发完,开始处理下组数据
cin >> input; //52张没发完,接着发牌
}
cout << (int)vec.size() << (vec.size() != 1 ? " piles remaining: ":" pile remaining: ");
rep(i, 0, (int)vec.size())
{
if ( i != vec.size() - 1 ) cout << vec[i].size() << " ";
else cout << vec[i].size() << endl;
}
vec.clear();
}
}
int main()
{
solve();
return 0;
}/* 查阅的其他资料: http://mikixiyou.iteye.com/blog/1754413 http://www.cnblogs.com/freeopen/p/5482962.html http://blog.csdn.net/glrh123/article/details/45542549 */