127 - "Accordian" Patience

题意:
移牌游戏,按以下规则:
1. 从左向右, 考虑每张牌, 若某张牌与其左边第1张或左边第3张是同一个牌号或花色, 则就把这张牌移到左边的匹配牌上方, 并继续向左边移动, 直至左边第1张或第3张都不是符合的牌为止.
2. 如果同时有两张以上的牌可以移动, 则总是移动最左边的牌.
3. 如果既可以移到左边第1张也可以移到左边第3张, 则总是移到左边第3张上面.
4. 如果某一列被移为空, 则把右边的牌合并过来.
5. 每次只取一列中最顶上的牌进行比较.
当所有牌都不能移动时, 从左到右输出每一列包含的张数.

思路:
1. 使用 list 存放每一列, 再使用 vector 存放所有的列.
2. 每次比较时, 在 vector 里从左到右依次取出一列, 比较其最顶的牌与其左边第1张、第3张牌是否为同一分组,若是同一分组, 则按"题意"规则 1, 3 进行移动.
3. 注意, 当一张牌移动完毕后, 应该从它移动到的牌的下一张开始重新循环, 而不是移动时的牌的下一张, 否则无法满足"题意"中的规则 2.

要点:
1. vector 的 erase 会自动把后(右)边的元素补上来, 正好满足这里的需要.
2. list 通过 push_front, push_back, pop_front, pop_back 来操纵其首尾元素.

题目:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=103&page=show_problem&problem=63

代码:

# include <iostream>
# include <string>
# include <cstdio>
# include <cstring>
# include <vector>
# include <algorithm>
# include <cctype>
# include <iterator>
# include <assert.h>
# include <list>
using namespace std;

// 1. 如果有两张牌可以移动,则总是移动最左的那张,即从左到右逐张牌进行处理
// 2. 如果一张牌 match 其左边第1张或第3张牌,就把它移过去
//    (要先移,即类似冒泡,而不是选择法),往复至不能移为止
// 3. 若同时满足两种情况,则移到最左边
// 4. match 是指两张牌在相同的 suit 或 rank
// 5. 只取第一张牌进行比较
// 6. 若出现某一列为空,则把它右边的列往左移 (vector earase 会自动做)


// 判断两张牌是否 match, 即判断其对应字符是否相等
bool isMatch(const string& str1, const string& str2) {
  assert(str1.size() == 2 && str2.size() == 2);
  return (str1[0] == str2[0] || str1[1] == str2[1]);
}

// 判断在 i 和 j 处的第一张牌是否 match
bool isMatch(const vector< list<string>* > cards, int i, int j) {
  if (!(i>=0 && i<cards.size() &&
        j>=0 && j<cards.size())) 
    return false;

  list<string>::const_iterator itI, itJ;
  itI = cards[i]->begin();
  itJ = cards[j]->begin();

  return isMatch(*itI, *itJ);
}

// 将 from 处的 card 移到 to 处
// 返回值表示 move 后当前是否为空
bool moveCard(vector< list<string>* >& cards, int from, int to) {
  list<string>* pileFrom = cards[from];
  list<string>* pileTo = cards[to];

  list<string>::iterator it = pileFrom->begin();
  pileTo->push_front(*it);
  pileFrom->pop_front();

  return pileFrom->empty();
}

// 从 i 开始向右找到其能 match 到的点,直至最左端, 若没有,则返回 -1
int findMatch(const vector< list<string>* >& cards, int i) {
  if (isMatch(cards, i, i-3))  return i-3;
  if (isMatch(cards, i, i-1))  return i-1;
  return -1;
}


// 处理当前所有牌
void dealCards(vector< list<string>* >& cards) {
  while (true) {
    int i=0;  
    bool needMove = false;

    while (i<cards.size()) {
      int to = findMatch(cards, i);
      bool needShrink = false;  

      if (to != -1) {
        needMove = true;
        needShrink = moveCard(cards, i, to);
      }
      if (needShrink) {
        delete cards[i];    // 先把这块的空间释放掉 
        // erase 会自动把后面的合并上来
        cards.erase(cards.begin()+i);
      }
      // 如果移动了,则从移动后的位置开始重新计算, 
      // 这样才能保证有两个可以移动时,移动的是最左边的那个
      if (to != -1) {     
        i = to;
        continue;
      }

      i++;
    }

    // 如果全部都不需要 move 了,表示游戏结束
    if (!needMove) 
      break;
  }
}

int main(int argc, char const *argv[])
{
  #ifndef ONLINE_JUDGE
    freopen("127_i.txt", "r", stdin);  
    freopen("127_o.txt", "w", stdout); 
  #endif
  
  string card;

  while (!cin.eof()) {
    cin >> card;
    if (card == "#") break;

    // vector 存放所有的牌, 每一列都用一个 list 来存放
    vector< list<string>* > cards;
    list<string>* pile;
    pile = new list<string>;
    pile->push_front(card);
    cards.push_back(pile);

    // 读入后 51 张牌
    for (int i=0; i<51; i++) {
      cin >> card;

      pile = new list<string>;
      pile->push_front(card);
      cards.push_back(pile);
    }

    dealCards(cards);

    // 注意 pile 有单复数之分
    // printf("%d piles remaining: ", int(cards.size()));
    if (cards.size() > 1) {
      printf("%d piles remaining:", int(cards.size()));
    } else {
      printf("%d pile remaining:", int(cards.size()));
    }

    // 注意这里的空格是打在 size 前面的,不是打在后面
    // 否则会报 Presentation error
    for (int i=0; i<cards.size(); i++) {
      cout << " " << cards[i]->size();    
      delete cards[i];                // 输出完了,要释放空间  
    }
    cout << endl;
  }

  return 0;
}

环境: C++ 4.5.3 - GNU C++ Compiler with options: -lm -lcrypt -O2 -pipe -DONLINE_JUDGE

你可能感兴趣的:(uva,127,Accordian,Patience)