资讯详情

动态规划在星空图模式匹配中的C++实现

📅 2026/10/26 12:16:58 | 华诺云谱 👁 阅读
动态规划在星空图模式匹配中的C++实现
1. 题目背景与需求分析P7133 小P的星空是信息学奥赛NOI系列题目中的一道经典动态规划问题。题目描述了一个浪漫的场景小P在夜晚仰望星空将星星连成不同的星座图案。我们需要用C编写程序计算在给定的星空图中能够组成多少个特定的星座形状。这道题的核心考察点在于二维矩阵中的模式匹配动态规划在图形识别中的应用空间复杂度的优化处理实际解题时我们需要处理以下几个关键问题如何高效表示星空图和星座模板如何处理不同方向的星座变体旋转、镜像等如何优化匹配算法的时间复杂度2. 数据结构设计与输入处理2.1 星空图的存储结构对于N×M的星空图最直接的存储方式是二维字符数组const int MAX_N 1005; char starMap[MAX_N][MAX_N];但在实际比赛中考虑到内存限制和访问效率更推荐使用vector容器vectorstring starMap; int n, m; // 星空图的行列数 void input() { cin n m; starMap.resize(n); for(int i0; in; i) { cin starMap[i]; } }2.2 星座模板的表示星座模板通常较小比如3×3或5×5可以用相同方式存储。但需要考虑其所有可能的变体struct Constellation { vectorstring pattern; int size; void rotate90() { // 顺时针旋转90度 vectorstring newPattern(size, string(size, )); for(int i0; isize; i) { for(int j0; jsize; j) { newPattern[j][size-1-i] pattern[i][j]; } } pattern newPattern; } void mirror() { // 水平镜像 for(auto row : pattern) { reverse(row.begin(), row.end()); } } };3. 核心算法实现3.1 暴力匹配算法最直接的思路是枚举星空图中的每个位置检查是否匹配星座模板bool matchAt(const vectorstring map, const vectorstring pattern, int x, int y) { int psize pattern.size(); for(int i0; ipsize; i) { for(int j0; jpsize; j) { if(xi map.size() || yj map[0].size()) return false; if(pattern[i][j] ! . map[xi][yj] ! pattern[i][j]) return false; } } return true; } int countMatches(const vectorstring map, const Constellation c) { int count 0; for(int i0; imap.size()-c.size; i) { for(int j0; jmap[0].size()-c.size; j) { if(matchAt(map, c.pattern, i, j)) { count; } } } return count; }3.2 使用动态规划优化当星座模板较大时暴力匹配效率低下。可以采用动态规划预处理星空图vectorvectorint preprocess(const vectorstring map, char target) { int n map.size(), m map[0].size(); vectorvectorint dp(n1, vectorint(m1, 0)); for(int i1; in; i) { for(int j1; jm; j) { dp[i][j] dp[i-1][j] dp[i][j-1] - dp[i-1][j-1]; if(map[i-1][j-1] target) { dp[i][j]; } } } return dp; } bool fastMatch(const vectorvectorint dp, const Constellation c, int x, int y, char target) { int psize c.size; int expected 0; for(int i0; ipsize; i) { for(int j0; jpsize; j) { if(c.pattern[i][j] target) expected; } } int actual dp[xpsize][ypsize] - dp[x][ypsize] - dp[xpsize][y] dp[x][y]; return actual expected; }4. 完整解题代码实现结合上述思路完整的解题代码如下#include iostream #include vector #include algorithm using namespace std; struct Constellation { vectorstring pattern; int size; void rotate90() { vectorstring newPattern(size, string(size, )); for(int i0; isize; i) { for(int j0; jsize; j) { newPattern[j][size-1-i] pattern[i][j]; } } pattern newPattern; } void mirror() { for(auto row : pattern) { reverse(row.begin(), row.end()); } } void generateAllVariants(vectorConstellation variants) { variants.push_back(*this); // 生成3个旋转版本 for(int i0; i3; i) { rotate90(); variants.push_back(*this); } // 生成镜像版本 mirror(); variants.push_back(*this); // 生成镜像后的旋转版本 for(int i0; i3; i) { rotate90(); variants.push_back(*this); } } }; bool matchAt(const vectorstring map, const vectorstring pattern, int x, int y) { int psize pattern.size(); for(int i0; ipsize; i) { for(int j0; jpsize; j) { if(xi map.size() || yj map[0].size()) return false; if(pattern[i][j] ! . map[xi][yj] ! pattern[i][j]) return false; } } return true; } int countMatches(const vectorstring map, const Constellation c) { int count 0; for(int i0; imap.size()-c.size; i) { for(int j0; jmap[0].size()-c.size; j) { if(matchAt(map, c.pattern, i, j)) { count; } } } return count; } int main() { // 输入处理 int n, m, k; cin n m; vectorstring starMap(n); for(int i0; in; i) { cin starMap[i]; } cin k; Constellation c; cin c.size; c.pattern.resize(c.size); for(int i0; ic.size; i) { cin c.pattern[i]; } // 生成所有可能的星座变体 vectorConstellation variants; c.generateAllVariants(variants); // 去重 sort(variants.begin(), variants.end(), [](const Constellation a, const Constellation b) { return a.pattern b.pattern; }); variants.erase(unique(variants.begin(), variants.end(), [](const Constellation a, const Constellation b) { return a.pattern b.pattern; }), variants.end()); // 计算匹配总数 int total 0; for(const auto variant : variants) { total countMatches(starMap, variant); } cout total endl; return 0; }5. 算法优化与性能分析5.1 时间复杂度分析原始暴力算法的时间复杂度为 O(N×M×K×P²) 其中N,M是星空图尺寸K是星座变体数量最多8个P是星座模板尺寸使用动态规划预处理后可以优化到 O(N×M K×N×M)5.2 空间优化技巧在实际比赛中内存限制严格可以采用以下优化使用bitset压缩存储星座模板按行处理星空图减少内存占用复用预处理数组// 使用bitset表示星座模板 bitset32 patternBits[5]; // 假设最大星座尺寸为5×5 void convertToBitset(const vectorstring pattern) { for(int i0; ipattern.size(); i) { for(int j0; jpattern[i].size(); j) { if(pattern[i][j] ! .) { patternBits[i].set(j); } } } }6. 常见错误与调试技巧6.1 边界条件处理常见错误包括数组越界访问未考虑星座模板超出星空图边界的情况旋转和镜像操作实现错误调试建议先测试小规模数据如3×3星空图和2×2星座打印中间结果验证旋转/镜像是否正确使用assert检查数组访问6.2 输入输出优化对于大规模数据使用快速IO方法避免不必要的endlios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);7. 测试用例设计7.1 基础测试用例3 3 *.* .*. *.* 1 3 *.* .*. *.*预期输出1完全匹配7.2 旋转测试用例4 4 ..*. .*.. *... ...* 1 3 *.. .*. ..*预期输出2匹配原始和旋转版本7.3 边界测试用例2 2 ** ** 1 2 *. .*预期输出0虽然元素相同但模式不匹配8. 竞赛实战建议模板准备提前准备好常用数据结构如二维数组处理、旋转操作等的代码模板测试驱动先写简单的测试用例验证基本功能再逐步增加复杂度性能预估根据题目约束条件估算算法复杂度确保在时间限制内调试输出在关键步骤添加有条件调试输出便于快速定位问题#define DEBUG 1 #if DEBUG #define debug(x) cout #x x endl #else #define debug(x) #endif在解决这类图形模式匹配问题时最重要的是建立清晰的思维模型。先考虑最简单的情况再逐步增加复杂度。实际比赛中通常不需要实现最优算法而是在有限时间内写出正确且足够高效的解法。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑