问题描述
给定一个矩阵 A = ( a i j ) m × n \bm A=(a_{ij})_{m\times n} A=(aij)m×n,其中 a i j ∈ { 1 , 2 , ⋯ , 9 } a_{ij}\in\{1,2,\cdots,9\} aij∈{1,2,⋯,9},且满足 ∑ i = 1 m ∑ j = 1 n a i j \sum\limits_{i=1}^m\sum\limits_{j=1}^na_{ij} i=1∑mj=1∑naij被10整除。玩家每次操作需要选择 A \bm A A中某个所有非空元素之和为10的子矩阵,并将其中所有的元素都标记为空。求按何种顺序消除能将 A \bm A A中所有的元素都标记为空,若存在则返回该解决方案,否则返回空列表。
代码
nursery_game.h
#ifndef NURSERY_GAME
#define NURSERY_GAME
#include <vector>
#include <stdint.h>
struct Operate {
uint8_t x1, y1, x2, y2;
Operate() {}
Operate(uint8_t i1, uint8_t j1, uint8_t i2, uint8_t j2):x1(i1), y1(j1), x2(i2), y2(j2) {}
};
std::vector<Operate> solve(int8_t *data, uint8_t m, uint8_t n);
#endif
nursery_game.cpp
#include "nursery_game.h"
#include <utility>
using std::vector;
// #define RECOVER_DATA // 若希望不改变A的值请解开本行注释
#define handle(x1,y1,x2_start,tag) for(uint8_t x2=x2_start;x2<m;){uint8_t ie=x2*n;for(uint8_t y2=y1;y2<n;y2++){uint8_t sum=0;for(uint8_t i=is;i<=ie;i+=n)for(uint8_t j=i+y1,e=i+y2;j<=e;j++){int8_t t=A[j];if(t>0&&(sum+=t)>10)goto tag;}if(sum!=10)continue;vector<uint8_t> set;for(uint8_t i=is;i<=ie;i+=n)for(uint8_t j=i+y1,e=i+y2;j<=e;j++){int8_t t=A[j];if(t>0){A[j]=-t;set.push_back(j);}}R.emplace_back(x1,y1,x2,y2);unRemoveCount-=set.size();posSet.push_back(std::move(set));goto F_push;}tag:x2++;}
// A: 矩阵A数据,逐行排列
// m: 矩阵A行数
// n: 矩阵A列数
vector<Operate> solve(int8_t *A, uint8_t m, uint8_t n) {
vector<Operate> R;
vector<vector<uint8_t>> posSet;
Operate op;
uint8_t unRemoveCount = m * n, is;
F_push:
if (!unRemoveCount) {
#ifdef RECOVER_DATA
int8_t *p = A + m * n;
do {
--p;
*p = -*p;
} while (p != A);
#endif
return std::move(R);
}
is = 0;
for (uint8_t x1 = 0; x1 < m; x1++, is += n)
for (uint8_t y1 = 0; y1 < n; y1++)
handle(x1, y1, x1, F1)
F_pop:
if (R.empty()) return {};
op = R.back();
R.pop_back();
unRemoveCount += posSet.back().size();
for (auto pos : posSet.back()) A[pos] = -A[pos];
posSet.pop_back();
is = op.x1 * n;
handle(op.x1, op.y1, op.x2 + 1, F2)
for (uint8_t y1 = op.y1 + 1; y1 < n; y1++) handle(op.x1, y1, op.x1, F3)
for (uint8_t x1 = op.x1 + 1; x1 < m; x1++) {
is += n;
for (uint8_t y1 = 0; y1 < n; y1++) handle(x1, y1, x1, F4)
}
goto F_pop;
}
test.cpp
#include "nursery_game.h"
#include <stdio.h>
using namespace std;
int main() {
int8_t data[] = { 4,7,3,3,6,5,4,4,2,1,8,4,2,2,2,6,1,2,3,2,3,2,7,1,2,8,1,3,1,6,4,5,4,5,1,4,2,2,2,3,8,3,3,1,9,2,3,3,1,1,4,4,1,9,3,7,1,3,2,5,3,1,1,5 };
vector<Operate> r(solve(data, 8, 8));
for (auto op : r) printf("(%d,%d) (%d,%d)\n", op.x1, op.y1, op.x2, op.y2);
return 0;
}
测试结果
(0,1) (0,2)
(0,0) (2,1)
(0,0) (3,1)
(0,7) (1,7)
(1,3) (1,6)
(0,4) (3,4)
(1,3) (5,3)
(0,3) (2,5)
(0,3) (4,5)
(0,4) (6,4)
(2,0) (2,6)
(0,2) (4,2)
(0,2) (4,6)
(5,0) (7,0)
(5,7) (6,7)
(6,0) (7,2)
(5,0) (6,3)
(0,1) (5,6)
(0,5) (7,5)
(4,0) (6,7)
(3,7) (7,7)
(0,0) (7,7)
操作过程:
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » (C++回溯算法)微信小程序“开局托儿所”游戏
发表评论 取消回复