488_祖玛游戏_2021.11.9

你正在参与祖玛游戏的一个变种。

在这个祖玛游戏变体中,桌面上有 一排 彩球,每个球的颜色可能是:红色 'R'、黄色 'Y'、蓝色 'B'、绿色 'G' 或白色 'W' 。你的手中也有一些彩球。

你的目标是 清空 桌面上所有的球。每一回合:

从你手上的彩球中选出 任意一颗 ,然后将其插入桌面上那一排球中:两球之间或这一排球的任一端。
接着,如果有出现 三个或者三个以上 且 颜色相同 的球相连的话,就把它们移除掉。
如果这种移除操作同样导致出现三个或者三个以上且颜色相同的球相连,则可以继续移除这些球,直到不再满足移除条件。
如果桌面上所有球都被移除,则认为你赢得本场游戏。
重复这个过程,直到你赢了游戏或者手中没有更多的球。
给你一个字符串 board ,表示桌面上最开始的那排球。另给你一个字符串 hand ,表示手里的彩球。请你按上述操作步骤移除掉桌上所有球,计算并返回所需的 最少 球数。如果不能移除桌上所有的球,返回 -1 。

 

 

 

 

 

 DFS求解过程:

  1 class Solution {
  2 public: 
  3         int ans, used;
  4     unordered_map<char, int> rem;    //记录hand中各彩球个数的字典
  5     stack<pair<char, int>> st;            //记录board中各彩球的个数的栈
  6 
  7     void dfs(int pos, string &board) {
  8         // 判断球是否用尽
  9         if (used >= ans)
 10             return;
 11 
 12         // 判断桌上球的遍历位置是否结束
 13         if (pos == board.size()) {
 14             // 判断
 15             if (st.empty())
 16                 ans = used;
 17             return;
 18         }
 19 
 20         // 将pos位置的小球加入
 21         if (!st.empty() && st.top().first == board[pos]) {
 22             st.top().second++;
 23         }
 24         else {
 25             st.emplace(board[pos], 1);
 26         }
 27 
 28         if (st.top().second >= 3) {
 29             if (pos + 1 == board.size() || board[pos + 1] != board[pos]) {
 30                 // 后面没有相同颜色的球,可以直接消去
 31                 auto tmp = st.top();
 32                 st.pop();
 33                 dfs(pos + 1, board);
 34                 st.push(tmp);
 35             }
 36             else {
 37                 // 后面有相同颜色的球,必须插入与当前位置不同色的小球进行分隔后,才能将当前积累的小球消去;否则必须和后面的同色球一起消去。
 38                 auto tmp = st.top(); // 维护现场
 39                 st.pop(); // 消去当前积累的同色小球
 40 
 41                 for (auto [ch, num] : rem) {
 42                     if (ch == board[pos])
 43                         continue;
 44                     for (int j = 1; j <= min(3, num); ++j) {
 45                         rem[ch] -= j;
 46                         used += j;
 47 
 48                         // 加入j个小球
 49                         if (!st.empty() && st.top().first == ch) {
 50                             st.top().second += j;
 51                         }
 52                         else {
 53                             st.emplace(ch, j);
 54                         }
 55 
 56                         if (st.top().second >= 3) { // 插入的异色球和之前的球累加达到了三个
 57                             auto tmp2 = st.top(); // 维护现场
 58                             st.pop(); // 消去同色球
 59                             dfs(pos + 1, board);
 60                             st.push(tmp2); // 还原现场
 61                         }
 62                         else {
 63                             dfs(pos + 1, board);
 64                         }
 65 
 66                         // 还原现场
 67                         if (st.top().second > j) {
 68                             st.top().second -= j;
 69                         }
 70                         else {
 71                             st.pop();
 72                         }
 73                         used -= j;
 74                         rem[ch] += j;
 75                     }
 76                 }
 77 
 78                 st.push(tmp); // 还原现场
 79             }
 80         }
 81 
 82         // 插入与当前位置同色的小球
 83         if (rem[board[pos]] >= 1 && (pos + 1 == board.size() || board[pos + 1] != board[pos])) {
 84             int lim = rem[board[pos]];
 85             for (int i = 1; i <= min(2, lim); ++i) {
 86                 // 加入i个同色小球
 87                 rem[board[pos]] -= i;
 88                 used += i;
 89                 st.top().second += i;
 90                 if (st.top().second >= 3) { // 累积同色球达到三个
 91                     auto tmp = st.top(); // 维护现场
 92                     st.pop(); // 消去同色球
 93                     dfs(pos + 1, board);
 94                     st.push(tmp); // 还原现场
 95                 }
 96                 else {
 97                     dfs(pos + 1, board);
 98                 }
 99 
100                 // 还原现场
101                 st.top().second -= i;
102                 used -= i;
103                 rem[board[pos]] += i;
104             }
105         }
106 
107         // 不额外插入小球的情形
108         // 1. 当前颜色小球不满三个
109         // 2. 当前颜色小球满三个,但当前小球和下一小球同色,这说明初始情形为XX...XX,之后中间的小球被消去,从而形成了XXXX,这种情况是允许的。
110         if (st.top().second < 3 || (st.top().second == 3 && pos + 1 < board.size() && board[pos] == board[pos + 1]))
111             dfs(pos + 1, board);
112 
113         // 还原现场
114         if (st.top().second == 1) {
115             st.pop();
116         }
117         else {
118             st.top().second--;
119         }
120     }
121 public:
122     int findMinStep(string board, string hand) {
123         for (char ch : hand)
124             rem[ch]++;
125 
126         ans = 1e9;        //定义无穷大,实际作用是记录最终手上的球全部用完
127         used = 0;        //用过的球
128 
129         // 广度优先边路
130         dfs(0, board);
131 
132 
133         return ans == 1e9 ? -1 : ans;
134     }
135 };
136 
137 
138 int main(void)
139 {
140     string board = "WWRRBBWW";
141     string hand = "WRBRW";
142 
143     Solution *s = new Solution();
144     cout << s->findMinStep(board, hand) << endl;
145 
146     delete(s);
147 
148     getchar();
149     return 0;
150 }    

 

posted @ 2021-11-09 21:49  炫迈吃到爽  阅读(52)  评论(0编辑  收藏  举报