(C++回溯算法)微信小程序“开局托儿所”游戏

问题描述

给定一个矩阵 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

cpp 复制代码
#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

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

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)

操作过程:






















相关推荐
y1su8 分钟前
Leetcode 动态规划 模板
java·数据结构·算法·leetcode·动态规划
半杯咖啡半行码14 分钟前
C++11核心特性详解:从C++11到C++20 的现代C++指南
开发语言·c++
All for pursuit.1 小时前
【位运算-3】136.只出现一次的数字
数据结构·c++·算法·leetcode
MoRanzhi12031 小时前
106.正则问题(分治)
python·算法·正则表达式·蓝桥杯·递归·分治算法·字符串处理
suhan2 小时前
【数据结构】五、树:7.哈夫曼树、哈夫曼编码
数据结构·算法·排序算法
kkhimself2 小时前
POJ-3126
算法
suhan2 小时前
【数据结构】五、树:6.平衡二叉树AVL
数据结构·算法·排序算法
suhan2 小时前
【数据结构】五、树:5.二叉排序树BST
数据结构·算法·排序算法
爱读书的小胖2 小时前
80. 删除有序数组中的重复项 II
java·数据结构·算法
臻选云栗子3 小时前
PCDN跑不起来?先别甩锅给平台,问题可能出在这
算法·程序员