puzzle(0412)日历拼图

puzzle(0412)日历拼图:从图像识别到求解策略的完整技术解析 本文深入解析了日历拼图(Puzzle 0412)从图像识别到求解策略的完整技术方案。通过OpenCV图像处理、启发式搜索算法和以解生解优化技术,实现了高效求解7x8网格拼图问题。文章详细介绍了计算机视觉处理流程、算法设计框架以及工程实践中的性能优化技巧,为益智游戏开发和算法教学提供了实用参考。 阅读详情
AI摘要

该博客系统阐述了日历拼图这一组合覆盖问题的算法解决方案,涵盖启发式搜索策略(如最小剩余值、复杂区域优先)、图像数字化流程(二值化、边缘检测、轮廓分析、格子定位与空位解析)及以解生解机制(大拇指/U型变换)。重点实现从原始图片自动提取拼图布局,并结合DFS+剪枝直接求解全部12×31×7种日期组合,最终输出标准化数字解矩阵。

目录

一,规则

二,每日拼图

2022年2月

2022年3月

竖条下滑问题

2022年4月

2022年5月

2022年6月

三,术语

四,启发式搜索策略

1,数独

2,策略一

3,策略二

4,策略三

5,策略四

6,策略五

7,策略六

五,数字化

1,读取图片并二值化

2,边缘检测

3,轮廓检测

4,求解格子尺寸、坐标

5,计算有效轮廓数量

6,坐标微调

7,手动删减轮廓

8,解析空出来的3个格子

8,连通性计算

9,完整代码

六,以解生解

1,大拇指

2,可视化

3,U型

4,新解

5,日期汇总

6,完整代码V1

7,BUG修复

8,日期优化(完整代码V2)

9,BUG修复、新增检查(完整代码V3)

七,说明

八,直接求解

1,可视化V2版

2,直接求解


一,规则

每天根据月、日、星期去掉3个格子,剩下的格子刚好全部覆盖。

日历拼图有两千多组合,如果所有组合都能拼的话,那真的太神奇了。

二,每日拼图

2022年2月

根据下面的数字化的方法,2022年2月1日-2月28日的答案分别是:

2月1日周二
  1  0  1  8  2  2  0
  1  1  1  8  8  2  0
  0  3  3  9  8  2  2
 10  3  3  9  9  9  5
 10  4  3  5  5  5  5
 10  4  4  4  6  6  6
 10  4  7  7  7  0  6
  0  0  0  0  7  7  6
2月2日周三
  1  0  1  2  3  3  0
  1  1  1  2  2  3  0
  4  0  9  8  2  3  3
  4  9  9  8  2  5  5
  4  9  6  8 10  5  5
  4  4  6  8 10  7  5
  6  6  6 10 10  7  0
  0  0  0  0  7  7  7
2月3日周四
  1  0  1  2  3  3  0
  1  1  1  2  2  3  0
  4  4  0  2  2  3  3
  8  4  4  4  5  5  5
  8  6  9  9  9  5  7
  8  6  9 10 10  5  7
  8  6  6  6 10 10  7
  0  0  0  0  0  7  7
2月4日周五
 10 0 10  7  1  1  0
 10  10 10  7  7  1  0
  2  2  2  0 7  1  1
  2  4  8  8  8  3  3
  2  4  8  3  3  3  9
  4  4  4  6  5  5  9
  6  6  6  6  5  5  9
  0  0  0  0  5  0  9
2月5日周六
  1  0  2  2  3  3  0
  1  1  2  4  4  3  0
  8  1  2  4  0  3  3
  8  1  2  4  4 10  5
  8  6  9 10 10 10  5
  8  6  9  9  5  5  5
  6  6  6  9  7  7  7
  0  0  0  0  7  7  0
2月6日周日
  1  0  1  3  3  8  0
  1  1  1  3  8  8  0
  2  2  3  3  8  0  5
  9  2  4  4  5  5  5
  9  2 10  4  4  4  5
  9  2 10  6  6  6  7
  9 10 10  0  6  6  7
  0  0  0  0  7  7  7
2月7日周一
  1  0  1  2  2  2  0
  1  1  1  2  3  3  0
  8  8  8  2  4  3  0
  8 10 10  4  4  3  9
 10 10  5  4  4  3  9
  5  5  5  6  6  7  9
  5  6  6  6  0  7  9
  0  0  0  0  7  7  7
2月8日周二
  1  0  1  2  3  3  0
  1  1  1  2  2  3  0
  4  4  4  2  2  3  3
  0  4  8  5  5  5  5
  6  4  8  8  8  7  5
  6  9  9  9  9  7  7
  6  6  6 10 10  0  7
  0  0  0  0 10 10  7
2月9日周三
  1  0  1  2  3  3  0
  1  1  1  2  2  3  0
  4  4  4  8  2  3  3
  4  0  6  8  2  5  5
  4  9  6  8 10  5  5
  9  9  6  8 10  7  5
  9  6  6 10 10  7  0
  0  0  0  0  7  7  7
2月10日周四
  1  0  1  2  3  3  0
  1  1  1  2  2  3  0
  4  4  4  2  2  3  3
  5  4  0  6  6  6  8
  5  4  6  6  8  8  8
  5  5  5  7  7  7  7
  9  9  9  9 10 10  7
  0  0  0  0  0 10 10
2月11日周五
  1  0  1  8  2  2  0
  1  1  1  8  8  2  0
  9  3  3  3  8  2  2
  9  7  3  0  4  4  4
  9  7  3  6  6  5  4
  9  7  6  6  6  5  4
  7  7 10 10 10  5  5
  0  0  0  0 10  0  5

2月12日周六
  1  0  1  2  3  3  0
  1  1  1  2  2  3  0
  4  4  4  2  2  3  3
  8  4  5  5  0  6  6
  8  4  9  5  5  5  6
  8  9  9  7  7  7  6
  8  9 10 10 10  7  6
  0  0  0  0 10  7  0
2月13日周日
  1  0  1  2  3  3  0
  1  1  1  2  2  3  0
  4  4  4  4  2  3  3
  8  9  9  4  2  0  5
  8 10  9  9  5  5  5
  8 10  6  6  6  7  5
  8 10 10  0  6  7  7
  0  0  0  0  6  7  7
2月14日周一
  1  0  1  4  2  2  0
  1  1  1  4  7  2  0
  3  4  4  4  7  2  2
  3  3  3  3  7  5  0
  8  6  6  6  7  5  5
  8  6  6 10 10  9  5
  8  8 10 10 0 9  5
  0  0  0  0  9  9  9
2月15日周二
  7  0  1  8  8  8  0
  7  1  1  2  9  8  0
  7  1  1  2  9  9  3
  7  4  2  2  2  9  3
  0  4 10 10  3  3  3
  4  4 10 5  5  5  5
  4 10 10 5  6  0  6
  0  0  0  0  6  6  6
2月16日周三
  1  0  1  5  2  3  0
  1  1  1  5  2  3  0
  4  5  5  5  2  3  3
  4  4  4  6  2  7  3
  4  0  9  6  6  7  7
  9  9  9  6  6 10  7
  9  8  8  8  8 10 0
  0  0  0  0  8 10 10

2月17日周四
  1  0  2  2  2  3  0
  1  1  6  6  2  3  0
  4  1  6  5  2  3  3
  4  6  6  5  5  5  7
  4  4  0  5 10  8  7
  9  4  9 10 10  8  7
  9  9  9 10 10  8  7
  0  0  0  0  0  8  8
2月18日周五
  1  0  2  2  2  3  0
  1  2  2  3  3  3  0
  1  1  1  4  4  4  4
  5  5  5  5  8  8  6
  5  7  9  0  8  6  6
  7  7  9  8  8  6  6
  7  9  9  9 10 10 10
  0  0  0  0 10  0 10
2月19日周六
  1  0  1  10  10  10  0
  1  1  1  2  2  10  0
  3  4  4  2  2  10  6
  3  5  4  2  6  6  6
  3  5  4  4  0  7  6
  3  5  5  8  7  7  9
  8  8  8  8  7  9  9
  0  0  0  0  7  9  0
2月20日周日
  1  0  1  2  2  2  0
  1  1  1  3  2  7  0
  3  3  3  3  2  7  7
  4  5  5  5  6  6  7
  4  5  8  6  6  0  7
  4  5  8  10  10  9  9
  4  8  8  0  10  9  9
  0  0  0  0  10  10  9
2月21日周一
  1  0  1  2  2  2  0
  1  1  1  4  2  3  0
  4  4  4  4  2  3  3
  5  6  6  6  7  7  3
  5  6  8  8  8  7  0
  5  6  8  9  9  7  7
  5  9  9  9  0 10 10
  0  0  0  0 10 10 10
2月22日周二
  1  0  2  2  3  3  0
  1  1  1  2  4  3  0
  1  5  5  2  4  3  3
  5  5  6  6  4  4  4
  9  9  6  6  6  8  7
  0  9  8  8  8  8  7
  9  9 10 10 10  0  7
  0  0  0  0 10 10  7
2月23日周三
  1  0  1  2  3  3  0
  1  1  1  2  2  3  0
  4  4  4  4  2  3  3
  5  5  5  5  2  6  6
  7  7  7  5  9  6  6
  7  0  8  8  9 10  6
  7  8  8  9  9 10  0
  0  0  0  0 10 10 10
2月24日周四
  1  0  1  2  2  2  0
  1  1  1  5  3  2  0
  4  5  5  5  3  3  7
  4  5  6  6  6  3  7
  4  9  6  6  7  7  7
  4  9  0  8  8  8  8
  9  9  9 10 10 10  8
  0  0  0  0  0 10 10
2月25日周五
  2  0  1  1  1  1  0
  2  2  2  3  3  3  0
  2  5  5  3  4  4  4
  5  5  6  6  6  6  4
  7  8  8  9  9  6  4
  7  7  8 0  9  9  9
  7  7  8  8 10 10 10
  0  0  0  0 10  0 10
2月26日周六
  1  0  1  2  2  2  0
  1  1  1  3  2  4  0
  5  6  6  3  2  4  4
  5  7  6  3  3  3  4
  5  7  6  6  8  8  4
  5  7  7  9  0  8  8
  9  9  9  9 10 10 10
  0  0  0  0 10 10  0
2月27日周日
  1  0  1  5  5  2  0
  1  1  1  5  2  2  0
  3  4  5  5  2  2  7
  3  4  4  6  7  7  7
  3  9  4  6  6  6  6
  3  9  4  8  8  0 10
  9  9  9  0  8  8 10
  0  0  0  0 10 10 10
2月28日周一
  1  0  1  2  2  2  0
  1  1  1  5  2  3  0
  4  5  5  5  2  3  3
  4  5  6  6  7  7  3
  4  4  4  6  6  7  3
  8  9  9  9  9  7  0
  8  8  8  8  0 10 10
  0  0  0  0 10 10 10

拼的时候经常会出现,还有一块拼不上,而空出来的格子组成的是另一个块的形状的情况,如:

  

 

2月22日周二

拼的时候再次出现这种情况:

稍微调整就能得到:

2022年3月

2022年3月1日-3月31日的答案分别是:

3月1日周二
  1  1  0  2  2  2  0
  1  1  2  2  3  3  0
  0  1  6  4  4  3  5
  6  6  6  7  4  3  5
  6  8  9  7  4  3  5
  8  8  9  7  7  7  5
  8  9  9  9 10  0 10
  0  0  0  0 10 10 10
3月2日周三
  1  2  0  3  4  4  0
  1  2  2  3  3  4  0
  1  0  2  3  3  4  4
  1  1  2  5  5  5  5
  6  7  7  7  8  8  8
  6  7  9  9  8 10  8
  6  6  6  9  9 10  0
  0  0  0  0 10 10 10
3月3日周四
  1  2  0  2  5  5  0
  1  2  2  2  5  3  0
  1  4  0  5  5  3  3
  1  4  4  4  4  7  3
  6  6  6  7  7  7  9
  6  8  8  8  9  9  9
  6  8  8 10 10 10  9
  0  0  0  0  0 10 10
3月4日周五
  1  1  0  10  10  10  0
  3  1  1  1  2  10  0
  3  3  3  0  2  10  7
  3  4  6  6  2  2  7
  4  4  6  5  5  5  7
  4  6  6  5  5  7  7
  8  8  8  8  9  9  9
  0  0  0  0  9  0  9
3月5日周六
  1  2  0  2  3  3  0
  1  2  2  2  3  3  0
  1  4  4  4  0  3  9
  1  5  4  6  6  6  9
  7  5  4  6  8  8  9
  7  5  5  6  8  9  9
  7  7  5 8 8 10 10
  0  0  0  0 10 10  0
3月6日周日
  1  2  0  2  3  3  0
  1  2  2  2  3  3  0
  1  1  4  4  3  0  7
  5  1  4  6  7  7  7
  5  8  4  6  6  6  7
  5  8  4 10 10  6 9
  5  8  8 0 10 10 9
  0  0  0  0 9 9 9
3月7日周一
  1  1  0  2  2  2  0
  1  1  2  2  3  3  0
  1  5  4  4  4  3  0
  5  5  4  6  4  3  3
  5  6  6  6  7  7  7
  8  9  9  9  9 10  7
  8  8  8  8  0 10  7
  0  0  0  0 10 10 10
3月8日周二
  1  1  0  2  3  3  0
  1  1  1  2  2  3  0
  4  4  4  4  2  3  3
  0  5  5  5  6  6  6
  7  5  8  8  8  8  6
  7  7  7  9  9  8  6
  7  9  9  9 10  0 10
  0  0  0  0 10 10 10

3月9日周三
  1  1  0  2  2  3  0
  1  2  2  2  3  3  0
  1  1  7  7  3  3  4
  5  0  7  6  6  6  4
  5  7  7  6  8  8  4
  5  9  9  6  8 10  4
  5  5  9  9  8 10  0
  0  0  0  0 10 10 10
3月10日周四
  1  1  0  2  2  2  0
  3  1  1  2  5  5  0
  3  3  3  2  5  9  4
  3  6  0  5  5  9  4
  6  6  7  7  7  9  4
  6  8  7  8  9  9  4
  6  8  8  8 10 10 10
  0  0  0  0  0 10 10
3月11日周五
  1  1  0  2  3  3  0
  4  1  1  2  2  3  0
  4  4  4  2  2  3  3
  4  7  5  0  6  6  6
  7  7  5  5  5  5  6
  7  8  9  9  9  9  6
  7  8  8  8 10 10 10
  0  0  0  0 10  0 10
3月12日周六
  1  2  0  2  3  3  0
  1  2  2  2  5  3  0
  1  4  5  5  5  3  3
  1  4  4  6  0  8  8
  7  4  4  6  8  8 10
  7  7  7  6  6  6 10
  7  9  9  9  9 10 10
  0  0  0  0  9 10  0
3月13日周日
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  1  4  4  4  3  3
  5  5  5  5  4  0  7
  5  6  6  6  6  7  7
  8  8  9  9  9  7 10
  8  8  8  0  9  9 10
  0  0  0  0 10 10 10
3月14日周一
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  1  1  4  4  3  3
  5  6  6  4  9  7  0
  5  6  8  9  9  7  7
  5  6  8  9  9 10  7
  5  6  8  8  0 10  7
  0  0  0  0 10 10 10
3月15日周二
  1  1  0  2  3  3  0
  1  1  1  2  3  4  0
  5  5  5  2  3  4  4
  5  7  5  2  3  6  4
  0  7  9  6  6  6  8
  7  7  9  6  8  8  8
  9  9  9 10 10  0  8
  0  0  0  0 10 10 10
3月16日周三
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  1  1  4  4  3  3
  5  5  8  4  6  7  7
  5  0  8  9  6  7  7
  5  8  8  9  6 10  7
  5  8  9  9  6 10  0
  0  0  0  0 10 10 10
3月17日周四
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  1  7  5  4  3  3
  6  7  7  5  4  4  4
  6  7  0  5  5  8  8
  6  9  9  9  5 10  8
  6  9  9 10 10 10  8
  0  0  0  0  0 10  8

3月18日周六
  1  2  0  6  3  3  0
  1  2  2  6  4  3  0
  1  5  2  6  4  3  3
  1  5  6  6  4  4  4
  7  5  5  0  8  8  8
  7  7  7  9  9  8  8
  7  9  9  9 10 10 10
  0  0  0  0 10  0 10
3月19日周六
  1  2  0  2  3  3  0
  1  2  2  2  5  3  0
  1  4  5  5  5  3  3
  1  4  4  6  5  7  7
  8  8  4  6  0  7  7
  8  9  4  6  6  6  7
  8  9  9  9  9 10 10
  0  0  0  0 10 10  0
3月20日周日
  1  2  0  2  3  3  0
  1  2  2  2  5  3  0
  1  4  4  5  5  3  3
  1  4  10 5  8  8  8
  7  4  10 8  8  0 6
  7  4 10 10 6 6 6
  7  7  7  0 9 9 6
  0  0  0  0 9 9 9
3月21日周一
  1  2  0  2  3  3  0
  1  2  2  2  5  3  0
  1  4  4  5  5  3  3
  1  1  4  5  7  7  7
  6  6  4  7  7  8  0
  6  6  6  8  8  8 10
  9  9  9  9  0  8 10
  0  0  0  0 10 10 10
3月22日周二
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  1  1  4  4  3  3
  5  5  5  4  8  8  6
  5  9  7  8  8  8  6
  0  9  7  7  7  7  6
  9  9  9 10 10  0  6
  0  0  0  0 10 10 10
3月23日周三
  1  2  0  3  4  4  0
  1  2  2  3  3  4  0
  1  1  2  3  3  4  4
  5  5  5  5  6  6  6
  5  7  7  7  7  9  6
  8  0  8  9  9  9  6
  8  8  8 10 10  9  0
  0  0  0  0 10 10 10
3月24日周四
  1  2  0  2  3  3  0
  1  2  2  2  5  3  0
  1  4  4  4  5  3  3
  1  4  5  5  5  7  7
  6  6  6  6  7  7  9
  8  8  0  6  9  9  9
  8  8  8 10 10 10  9
  0  0  0  0  0 10 10
3月25日周五
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  7  5  5  4  3  3
  1  7  5  6  4  4  4
  7  7  5  6  6  6  6
  7  9  9  0 10  8  8
  9  9 10 10 10  8  8
  0  0  0  0 10  0  8
3月26日周六
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  1  4  4  4  3  3
  5  5  5  5  4  6  6
  7  8  8  9  9  9  6
  7  7  8  8  0  9  6
  7  7 10 10 10  9  6
  0  0  0  0 10 10  0
3月27日周日
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  1  6  7  4  3  3
  5  6  6  7  4  4  4
  5  6  7  7  7  8  8
  5  6 10 10  9  0  8
  5 10 10  0  9  9  8
  0  0  0  0  9  9  8
3月28日周一
  1  2  0  3  3  3  0
  1  2  2  2  2  3  0
  1  1  4  5  5  3  7
  6  1  4  5  7  7  7
  6  6  4  5  5  9  7
  8  6  4  9  9  9  0
  8  8  8  9  0 10 10
  0  0  0  0 10 10 10
3月29日周二
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  5  5  5  4  3  3
  1  7  6  5  4  4  4
  7  7  6  6  6  6  9
  7  8  8  8  9  9  9
  0  8  8 10 10  0  9
  0  0  0  0 10 10 10
3月30日周三
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  5  5  6  4  3  3
  1  5  6  6  4  4  4
  7  5  6  8  8  8  8
  7  7  7  9  9  9  8
  7  0  9  9 10 10  0
  0  0  0  0 10 10 10

3月31日周四
  1  2  0  2  3  3  0
  1  2  2  2  4  3  0
  1  4  4  4  4  3  3
  1  5  5  5  6  6  6
  7  7  8  5  6  6  9
  7  8  8  5  9  9  9
  7  8  0 10 10 10  9
  0  0  0  0  0 10 10

竖条下滑问题

因为是平放在桌面上拼的,所以经常忘了竖条下面不能放空格,然后每次我都会重新拼。

2月5日周六

 

3月9日周三

4月2日周六

2022年4月

4月1日周五
  1  1  2  0  3  3  0
  1  1  2  2  2  3  0
  0  1  2  5  5  3  3
  4  5  5  5  6  6  6
  4  8  9  9  9  9  6
  4  8  8 10 10 10  6
  4  4  8 10  7  7  7
  0  0  0  0  7  0  7
4月2日周六
  1  1  2  0  2  3  0
  1  1  2  2  2  3  0
  1  0  4  4  3  3  3
  4  4  4  5  8  8  8
  6  6  6  5  5  5  8
  6  9  9  9  9  5 10
  6  7  7  7  7 10 10
  0  0  0  0  7 10  0
4月3日周日
  1  1  1  0  2  2  0
  8  1  3  3  3  2  0
  8  1  0  3  3  2  2
  8  4  4  4  5  6  6
  8  4  9  9  5  5  6
  7  4  7  9  9  5  6
  7  7  7  0 10  5  6
  0  0  0  0 10 10 10

4月4日周一
  6  6  1  0  1  2  0
 7  6  1  1  1  2  0
  7  6  6 0  2  2  2
  7  7  7  4  4  8  9
  3  4  4  4  8  8  9
  3  3  3  3  8  9  9
 10 10 10 10  0  5  5
  0  0  0  0  5  5  5
4月5日周二
  8  1  1  0  2  2  0
  8  3  1  1  1  2  0
  8  3  3  3  0  2  2
  8  3 10 10  4  4  5
  9 10 10  4  4  4  5
  9  9  9  6  5  5  5
  6  6  6  6  7  0  7
  0  0  0  0  7  7  7
4月6日周三
  1  1  1  0  3  3  0
  1  2  2  3  3  3  0
  1  4  2  2  2  0  5
  8  4  4  4  5  5  5
  8  9  9  4  6  6  5
  8  8  9  9  6  7  7
 10 10 10 10  6  7  0
  0  0  0  0  6  7  7

4月7日周四
  1  1  2  0  2  4  0
  3  1  2  2  2  4  0
  3  1  1  4  4  4  0
  3  3  5  5  5  8  8
  6  3  5  5  8  8  7
  6  6  6  9  9  9  7
  6 10 10 10 10  9  7
  0  0  0  0  0  7  7
4月8日周五
  1  1  2  0  2  4  0
  1  1  2  2  2  4  0
  1  5  5  3  4  4  4
  0  5  7  3  3  3  3
  5  5  7  6  8  8  8
  7  7  7  6  6  9  8
 10 10 10 10  6  9  9
  0  0  0  0  6  0  9

4月9日周六
  1  1  2  0  2  4  0
  1  3  2  2  2  4  0
  1  3  3  3  4  4  4
  1  0  8  3  6  6  6
  5  8  8  6  6  9  9
  5  8 10 10 10 10  9
  5  5  5  7  7  7  9
  0  0  0  0  7  7  0

4月10日周日
  1  1  2  0  2  4  0
  1  3  2  2  2  4  0
  1  3  3  3  4  4  4
  1  6  0  3  5  5  5
  6  6  8  8  8  8  5
  6  7  7  7  9  9  5
  6  7  7  0 10  9  9
  0  0  0  0 10 10 10

4月11日周一
  1  1  2  0  3  3  0
  1  1  2  2  2  3  0
  7  1  2 10  10  3  3
  7  7  4 0 10 10 10
  5  7  4  4  4  4  8
  5  9  9  9  6  6  8
  5  5  5  9  0  6  8
  0  0  0  0  6  6  8
4月12日周二
  1  1  2  0  3  3  0
  1  1  2  2  2  3  0
  4  1  2  5  5  3  3
  4  5  5  5  0  8  8
  4  4  4  6  8  8  9
  6  6  6  6  9  9  9
 10 10 10 10  7  0  7
  0  0  0  0  7  7  7
4月13日周三
  1  1  2  0  2  3  0
  8  1  2  2  2  3  0
  8  1  1  5  4  3  3
  8  5  5  5  4  0  3
  8 10 10  5  4  4  4
 10 10  9  6  6  6  6
  9  9  9  6  7  7  0
  0  0  0  0  7  7  7

4月14日周四
  1  1  1  0  2  2  0
  1  3  3  3  4  2  0
  1  7  3  8  4  2  2
  5  7  3  8  4  4  0
  5  7  7  8  6  4  6
  5  9  9  8  6  6  6
  5  5  9  9 10 10 10
  0  0  0  0 10 10  10
4月15日周五
  1  1  8  0  2  2  0
  1  3  8  8  4  2  0
  1  3  3  8  4  2  2
  1  6  3  9  4  4  4
  0  6  3  9  5  5  5
  6  6  6  9  9  5  5
 10 10 10 10  7  7  7
  0  0  0  0  7  0  7

4月16日周六
  1  1  2  0  2  4  0
  1  3  2  2  2  4  0
  1  3  3  3  4  4  4
  1  5  5  3  8  8  8
  6  0  5  5  5  9  8
  6 10 10 10 10  9  9
  6  6  6  7  7  7  9
  0  0  0  0  7  7  0

4月17日周日
  8  1  2  0  2  3  0
  8  1  2  2  2  3  0
  8  1  9  9  3  3  3
  8  1  1  9  9  5  5
  4 10  0  5  5  5  6
  4 10 10 10  6  6  6
  4  4  4  0  6  7  7
  0  0  0  0  7  7  7
4月18日周一
  1  1  2  0  2  3  0
 10  1  2  2  2  3  0
 10  1  1  3  3  3  4
 10  10  7  4  4  4  4
  5 10  7 0  9  8  8
  5  5  7  9  9  6  8
  5  5  7  9  0  6  8
  0  0  0  0  6  6  6

4月19日周二
  1  1  2  0  2  4  0
  1  3  2  2  2  4  0
  1  3  3  3  4  4  4
  1  5  5  3  8  8  8
  6  5  5  5  0  7  8
  6  9  9  9  9  7  7
  6  6  6 10 10  0  7
  0  0  0  0 10 10  7

4月20日周三
  1  1  2  0  2 10  0
  1  7  2  2  2  10  0
  1  7  7  7 10 10 10
  1  8  9  9  9  9  5
  3  8  8  6  6 0  5
  3  3  8  6  4  5  5
  3  3  6  6  4  5  0
  0  0  0  0  4  4  4
4月21日周四
  7  1  2  0  2  3  0
  7  1  2  2  2  3  0
  7  1  1  1  4  3  3
  7  4  4  4  4 10  3
  8  8  9  5  5  10 0
  8  9  9  5 10 10 10
  8  9  5  5  6  6  6
  0  0  0  0  0  6  6

4月22日周五
  1  2  2  0  3  3  0
  1  2  2  2  4  3  0
  1  1  5  5  4  3  3
  7  1  5  6  4  4  4
  7  7  5  6  6  6  8
  0  7  5  6  8  8  8
  9  9  9  9 10 10 10
  0  0  0  0 10  0 10

4月23日周六
  8  1  2  0  2  3  0
  8  1  2  2  2  3  0
  8  1  1  1  3  3  3
  8  5  7  4  9  9  9
  5  5  7  4  4  4  9
  5  0  7  6  6  4 10
  5  7  7  6  6 10 10
  0  0  0  0  6 10  0

4月24日周日
  1  2  3  0  3  4  0
  1  2  3  3  3  4  0
  1  2  2  2  4  4  4
  1  1  5  5  5  8  8
  9  9  9  9  5  5  8
  6  6  0  7  7 10  8
  6  6  6  0  7 10 10
  0  0  0  0  7  7 10

4月25日周一
  8  1  1  0  2  2  0
  8  8  1  1  1  2  0
  9  8  3  3  3  2  2
  9  6  3  3  4  4  4
  9  6  5  5  4 10 10
  9  6  5  0  4  7 10
  6  6  5  5  0  7 10
  0  0  0  0  7  7  7

4月26日周二
  1  1  2  0  3  3  0
  1  1  2  2  2  3  0
  4  1  2  5  5  3  3
  4  5  5  5  8  9  9
  4  4  4  6  8  8  9
  6  6  6  6  0  8  9
 10 10 10 10  7  0  7
  0  0  0  0  7  7  7

4月27日周三
  8  8  1  0  1  2  0
  9  8  1  1  1  2  0
  9  8 10 10  2  2  2
  9 10 10  4  3  3  3
  9  4  4  4  6  6  3
  5  4  6  6  6  0  3
  5  5  5  5  7  7  0
  0  0  0  0  7  7  7

4月28日周四
  1  1  2  0  2  5  0
  3  1  2  2  2  5  0
  3  1  1  4  5  5  5
  3  3  3  4  4  4  4
  8  8 10  9  9  9  9
  8 10 10  6  6  6  0
  8 10  6  6  7  7  7
  0  0  0  0  0  7  7

4月29日周五
  1  1  1  0  2  2  0
  1  3  3  3  3  2  0
  1  9  9  8  3  2  2
  9  9  4  8  5  5  5
  4  4  4  8 10  5  5
  6  6  4  8 10 10 10
  0  6  6  6  7  7  7
  0  0  0  0  7  0  7
4月30日周六
  1  1  2  0  2  5  0
  1  1  2  2  2  5  0
  1  3  3  4  5  5  5
  8  6  3  4  4  4  4
  8  6  3  3  9  9  9
  8  6  6  6  7  7  9
  8  0  7  7  7 10 10
  0  0  0  0 10 10  0

2022年5月

5月1日周日
  1  1  1  2  0  2  0
  1  1  8  2  2  2  0
  0  4  8  9  9  3  3
  4  4  8 10  9  9  3
  4  7  8 10  5  5  3
  4  7 10 10  6  5  3
  7  7  7  0  6  5  5
  0  0  0  0  6  6  6

5月2日周一
  1  1  2  3  0  3  0
  1  1  2  3  3  3  0
  1  0  2  2  2  6  6
  4  4  5  6  6  6  8
  9  4  5  5  5  5  8
  9  4  4 10 10  7  8
  9  9 10 10  0  7  8
  0  0  0  0  7  7  7
5月3日周二
  1  1  1  2  0  2  0
  1  4  4  2  2  2  0
  1  4  0  3  8  8  5
  4  4  6  3  8  5  5
  6  6  6  3  8  5  9
  7  7  6  3  3  5  9
  7  7  7 10 10  0  9
  0  0  0  0 10 10  9

 5月4日周三
  8  8  8  8  0  1  0
  2  2  3  3  3  1  0
  2  4  3  0  3  1  1
  2  4  4  4 10  9  1
  2  6  5  4 10  9  9
  6  6  5 10 10  7  9
  6  6  5  5  5  7  0
  0  0  0  0  7  7  7
5月5日周四
  8  1  1  2  0  2  0
  8  3  1  2  2  2  0
  8  3  1  1  0  4  4
  8  3  3  3  9  4  4
  5  5  9  9  9  4  7
  6  5  5  5  7  7  7
  6  6  6  6 10 10  7
  0  0  0  0  0 10 10

5月6日周五
  1  1  1  2  0  2  0
  1  3  3  2  2  2  0
  1  4  3  3  3  0  5
  8  4  4  4  5  5  5
  8  9  9  4  6  6  5
  8 10  9  9  6  7  7
  8 10 10 10  6  7  7
  0  0  0  0  6  0  7

5月7日周六
  1  1  1  1  0  2  0
  1  9  8  2  2  2  0
  9  9  8  3  3  2  0
  9  4  8  3  5  5  5
 10  4  8  3  3  6  5
 10  4  4  6  6  6  5
 10 10  4  6  7  7  7
  0  0  0  0  7  7  0

5月8日周日
  1  1  1  1  0  2  0
  1  3  3  3  5  2  0
  4  4  3  5  5  2  2
  0  4  3  5  5  8  2
  6  4  4  8  8  8 10
  6  9  9  9  9 10 10
  6  6  6  0  7 10  7
  0  0  0  0  7  7  7

5月9日周一
  1  2  2  3  0  3  0
  1  1  2  3  3  3  0
  1  1  2  2  5  5  5
  8  0  4  5  5 10  9
  8  8  4 10 10 10  9
  6  8  4  4  4  7  9
  6  6  6  6  0  7  9
  0  0  0  0  7  7  7

5月10日周二
  1  1  1  2  0  2  0
  1  3  3  2  2  2  0
  1  3  8  8  8  8  4
  3  3  0  5  4  4  4
  5  5  5  5 10  9  4
  6  6 10 10 10  9  9
  6  6  6  7  7  0  9
  0  0  0  0  7  7  7

5月11日周三
  1  1  1  2  0  2  0
  1  1  3  2  2  2  0
  8  8  3  3  3  4  4
  5  8  8  0  3  6  4
  5  9  9  9  6  6  4
  5  5  5  9  6  7  4
 10 10 10 10  6  7  0
  0  0  0  0  7  7  7

5月12日周四
  1  1  2  3  0  3  0
  1  1  2  3  3  3  0
  8  1  2  2  4  4  4
  8  8  8  2  0  4  9
  5  5  5 10 10  4  9
  5  6 10 10  7  7  9
  5  6  6  6  6  7  9
  0  0  0  0  0  7  7

5月13日周五
  8  8  8  8  0  1  0
  9  9  2  2  2  1  0
 10  9  9  2  3  1  1
 10 10 10  2  3  0  1
  4  4  6  6  3  3  3
  4  4  6  5  5  5  5
  4  6  6  5  7  7  7
  0  0  0  0  7  0  7

5月14日周六
  1  1  1  2  0  2  0
  1  3  3  2  2  2  0
  1  3  3  8  8  4  4
  9  3 10 10  8  4  0
  9 10 10  5  8  4  7
  9  5  5  5  6  4  7
  9  5  6  6  6  7  7
  0  0  0  0  6  7  0

5月15日周日
  8  8  8  1  0  1  0
  2  9  8  1  1  1  0
  2  9  9 10 10 10 10
  2  2  9  3  3  3  3
  0  2  4  3  5  5  5
  6  6  4  4  4  7  5
  6  6  6  0  4  7  5
  0  0  0  0  7  7  7
5月16日周一
  1  1  1  2  0  2  0
  1  3  3  2  2  2  0
  1  8  3  4  4  5  5
  8  8  3  4  4  5  9
  8  0  3  4  5  5  9
 10 10 10  6  6  7  9
 10  6  6  6  0  7  9
  0  0  0  0  7  7  7

5月17日周二
  1  1  1  2  0  2  0
  1  8  8  2  2  2  0
  1  3  8  8  9  9  9
 10  3  3  3  3  5  9
 10  4  0  5  5  5  6
 10  4  4  5  6  6  6
 10  4  4  7  7  0  6
  0  0  0  0  7  7  7

5月18日周三
  1  1  1  2  0  2  0
  8  8  1  2  2  2  0
  9  8  1  3  3  4  4
  9  8 10  3  3  3  4
  9 10 10  0  6  6  4
  9 10  5  5  6  7  4
  5  5  5  6  6  7  0
  0  0  0  0  7  7  7
5月19日周四
  1  1  1  2  0  2  0
  8  1  4  2  2  2  0
  8  1  4  3  3  3  3
  8  4  4  3  5  5  5
  8  4 10 10  0  5  5
  9 10 10  6  7  7  7
  9  9  9  6  6  6  7
  0  0  0  0  0  6  7
5月20日周五
  8  1  1  1  0  2  0
  8  1  4  4  2  2  0
  8  1  4  5  2  3  3
  8  4  4  5  2  3  3
  9  9  5  5  5  0  3
 10  9  9  6  6  6  6
 10 10 10  6  7  7  7
  0  0  0  0  7  0  7

5月21日周六
  1  1  1  2  0  6  0
  1  2  2  2  3  6  0
  1  2  3  3  3  6  6
  7  7  7  4  3  4  6
  8  8  7  4  4  4 0
 10  8  8  9  9  9  9
 10 10 10 10  5  5  5
  0  0  0  0  5  5  0

5月22日周日
  8  1  9  9  0  2  0
  8  1 10  9  9  2  0
  8  1 10 10 10  2  2
  8  1  1  3  3  3  2
  5  5  4  3  3  6  6
  0  5  4  4  4  6  7
  5  5  4  0  6  6  7
  0  0  0  0  7  7  7

5月23日周一
  8  1  1  2  0  2  0
  8  8  1  2  2  2  0
  3  8  1  1  4  4  4
  3 10 10 10  4  4  9
  3  3  3 10  6  6  9
  5  0  6  6  6  7  9
  5  5  5  5  0  7  9
  0  0  0  0  7  7  7

5月24日周二
  8  1  1  2  0  2  0
  8  3  1  2  2  2  0
  8  3  1  1  9  9 10
  8  3  3  3  9 10 10
  4  4  4  4  9 10  6
  5  5  0  4  6  6  6
  5  5  5  7  7  0  6
  0  0  0  0  7  7  7

5月25日周三
  1  1  1  2  0  2  0
  1  1  3  2  2  2  0
  8  8  3  3  3  4  4
  5  8  8  9  3  6  4
  5  9  9  9  6  6  4
  5  5  5  0  6  7  4
 10 10 10 10  6  7  0
  0  0  0  0  7  7  7

5月26日周四
  8  1  1  2  0  2  0
  8  8  1  2  2  2  0
  3  8  1  1  5  4  4
  3  9  9  9  5  4  4
  3  9  5  5  5  4 10
  3  3  6  6  0  7 10
  6  6  6  7  7  7 10
  0  0  0  0  0  7 10

5月27日周五
  1  1  1  2  0  5  0
  1  2  2  2  3  5  0
  1  2  4  3  3  5  8
  4  4  4  3  5  5  8
  9  9  4  3 10 10  8
  9  6  6 10 10  0  8
  9  6  6  6  7  7  7
  0  0  0  0  7  0  7

5月28日周六
  1  1  1  2  0  2  0
  1  3  3  2  2  2  0
  1  9  3  8  8  8  8
  9  9  3  6 10 10 10
  9  5  3  6  4  4 10
  5  5  6  6  6  4  0
  5  5  7  7  7  4  4
  0  0  0  0  7  7  0

5月29日周日
  1  1  1  2  0  2  0
  3  1  4  2  2  2  0
  3  1  4  4  5  5  5
  3  3  4  4  5  6  6
  8  3  9  9  5  6 10
  8  8  9  7  7  6 10
  0  8  9  0  7  6 10
  0  0  0  0  7  7 10

5月30日周一
  8  1  1  2  0  2  0
  8  3  1  2  2  2  0
  8  3  1  1  9  9  9
  8  3  3  3  5 10  9
  4  5  5  5  5 10 10
  4  4  4  6  6  6 10
  4  0  6  6  0  7  7
  0  0  0  0  7  7  7

5月31日周二
  1  1  1  2  0  2  0
  1  1  3  2  2  2  0
  4  4  3  3  3  8  8
  7  4  3  8  8  8  5
  7  4  4  5  5  5  5
  7  9  9  9 10 10  6
  7  9 0 10 10  0  6
  0  0  0  0  6  6  6

2022年6月

6月1日周三
  1  2  2  3  3  0  0
  1  1  2  3  3  3  0
  0  1  2  2  4  4  4
  8  1  5  5  5  5  4
  8  9  9 10 10  5  4
  8  9 10 10  7  6  6
  8  9  7  7  7  6  0
  0  0  0  0  7  6  6

6月2日周四
  1  1  2  2  2  0  0
  1  1  4  3  2  2  0
  1  0  4  3  3  3  5
  4  4  4  3  5  5  5
  6  6  8  8  5  9  7
  6  8  8  9  9  9  7
  6  6 10 10 10 10  7
  0  0  0  0  0  7  7

6月3日周五
  1  2  3  3  3  0  0
  1  2  2  2  3  3  0
  1  2  0  7  7  9  8
  1  1  5  7  9  9  8
  4  5  5  7  9  6  8
  4  5  5  6  6  6  8
  4  4  4  6 10 10 10
  0  0  0  0 10 0 10

6月4日周六
  8  1  2  2  2  0  0
  8  1  2  4  4  3  0
  8  1  2  0  4  3  3
  8  1  1  4  4  5  3
  9  9 10  5  5  5  3
  9 10 10  5  7  6  6
  9 10  7  7  7  6  6
  0  0  0  0  7  6  0

三,术语

可行的匹配:把某个块放在某个位置之后,如果接下来还有解,那就是可行的匹配。

平坦区域:接近矩形的区域,没有十分明显的局部特征。

四,启发式搜索策略

1,数独

我构造了一个数独来显化这种启发式策略:

对于这个数独,没有任何疑问,首先看行填2,其次看列填5,然后看宫填9。

 现在我们来总结一下这个思维的本质。

有些人可能会这么描述:“先把确定的填了,再看不确定的”,或者“先把简单的填了,再看难的”。

这些说法没错,但是不够精确。

在一开始,单独看3个格子中的任意一个的话,E2有3种情况(看宫),分别是259,F2有2种情况(看列),分别是25,F3有1种情况(看行),是2

那么,在这个深度优先搜索问题中,我们的策略是,先把元素进行排序,情况少的元素往前排,即先搜索情况比较少的元素。这是深度优先搜索的常见优化技巧。

2,策略一

如果对于结构比较复杂的局部区域,有某种拼法是比较精巧的,那这就很可能是某个正确答案的一部分。

  

这样一条模糊的策略,是否正确?本质是啥?

首先,结构比较复杂的局部区域是问题的一种特征,精巧的覆盖是解的一种特征。

问题的特征告诉我们,这个位置的可能的情况比较少,而平坦位置的可能情况比较多。

解的特征告诉我们,有相对较高的概率这个一个可行的匹配,如果确实是一个可行匹配,那么在此匹配前提下的解是相对较多的。

也就是说,这其实暗含了下面列的很多条策略,没想到吧O(∩_∩)O哈哈~

3,策略二

先从结构比较复杂的局部区域开始拼,平坦的区域靠后拼。

此时我们和上面的数独对比,可以感受到,他们的核心逻辑是完成相同的。

通常情况下,被排除的3个格子、右上角、右下角都是结构比较复杂的局部区域。

4,策略三

我们在拼的时候经常需要评估,一个匹配的优劣程度。在面临选择时,我们优先选择直觉上更优的匹配。

直觉有点玄乎,但是我们可以看到我在上面给出的三月的解法有很多都是这样的:

可以说这就是很优的匹配。

PS:如果我一早就想通了这个策略,3月至少有20天这2个块就可以这么放。

对于4月,我相信这是一个不错的匹配:

5,策略四

先从复杂的块开始拼,简单的块靠后。

这个和策略二很相似,策略二其实是,复杂的局部区域有更少的可能性,策略四其实是,复杂的块有更少的可能性。

以下图为例感受一下简单块的可能性之多:

 即使到了最后一步,仍然有2种放法。

而如果留到最后的是复杂的块,就很可能是0-1种放法。

根据块的复杂程度,我简单分成三个梯度,复杂,中等,简单。

3个复杂的:

5个中等的:

2个简单的:

6,策略五

首先我们分析一下这个拼图的平直程度。

例子太多,我不一一列举。

我直接给出我总结出的规律,在同类puzzle中,日历拼图的平直程度是非常高的。

 为什么会这样呢?我认为主要是块本身的属性造成的。

我把日历拼图的10个块,在方格游戏中的17个格子中标示出来(去掉小于4个格子的只有17个)

1、3、4、7、11、14、16号这7个是没有的,而其中的1、3、4、7、14显然符合我在上面策略四中提到的“复杂的块”这个特征。

从某种程度上说,这个复杂其实说的就是不平直的程度。

日历拼图和方格游戏是两个极端。日历拼图为了每个组合都有解,选的主要是平直度较高的块,方格游戏其实不是覆盖问题,而是依赖角点进行区域拓宽的一种博弈游戏,所以选的主要是平直度较低的块。

上面的策略四是根据块的复杂性(平直度)进行排序,而这里的策略五只针对平直度低的块,以3月29日周二为例:

周二这个格子和L型的块是一个很差的匹配。

而这是一个非常好的匹配,这个块和边界完美贴合,和周二的匹配也非常好。

综上,策略五就是,月日周排除的三个格子,尤其是离边界还有一个距离的格子(如上周二),要放在块的折口处,但是不能放L型块的折口处,从而维持整个局面的平直性。

7,策略六

策略六是替换策略。

以2月4日周五为例,我拼成了这样:

乍一看无解,实际上答案已经出来了:

一般来说,最简单的替换是这2组:

五,数字化

利用边缘检测和其他图像处理技术,把一张包含答案的图片,转化成数字。

1,读取图片并二值化

Mat GetImage(int i)
{
	Mat img = imread("D:/p/img (" + to_string(i) + ").png", 0);
	resize(img, img, Size(0, 0), 0.5, 0.5);
	Mat src;
	threshold(img, src, 200, 255, THRESH_TRUNC);
	threshold(src, src, 100, 255, THRESH_TOZERO);
	return src;
}

2,边缘检测

	Mat src = GetImage(i);
	Canny(src, src, 200, 100, 3);
	cv::imshow("src" + to_string(i), src);

3,轮廓检测

    std::vector<std::vector<Point>> contours;
	std::vector<Vec4i> hierarchy;
	findContours(src, contours, hierarchy, RETR_LIST, CHAIN_APPROX_NONE, Point(0, 0));
	cout << contours.size() << endl;
	sort(contours.begin(), contours.end(), cmp< Point>);
	for (int i = 0; i < contours.size(); i++)cout << contours[i].size() << " ";

把轮廓按照点数排序,点最多的轮廓就是我们需要的轮廓。

4,求解格子尺寸、坐标

int GetSize(const vector<std::vector<Point>>& contours, int &xmin ,int &ymin)
{
	xmin = 1234567, ymin = 1234567;
	int xmax = 0, ymax = 0;
	for (int i = 0; i < 5 && i < contours.size(); i++) {
		for (auto& pi : contours[i]) {
			if (xmin > pi.x)xmin = pi.x;
			if (ymin > pi.y)ymin = pi.y;
			if (xmax < pi.x)xmax = pi.x;
			if (ymax < pi.y)ymax = pi.y;
		}
	}
	int dx = xmax - xmin, dy = ymax - ymin;
	dx /= 7, dy /= 8;
	cout << endl << dx << endl << dy;
	return dx;
}

其中for循环控制的是取前多少个轮廓,否则很容易受到最外面的轮廓的影响。

xmin和ymin记录了左上角的格子坐标。

5,计算有效轮廓数量

为了更有效的计算格子尺寸,需要更智能的选择轮廓数量。

void GetContoursNum(Mat src, const vector<std::vector<Point>>& contours)
{
	bool xmin=false, xmax = false, ymin = false, ymax = false;
	contoursNum = 0;
	for (contoursNum = 0; contoursNum < contours.size(); contoursNum++) {
		for (auto &pi : contours[contoursNum]) {
			if (src.cols / 7 > pi.x)xmin = true;
			if (src.rows / 8 > pi.y)ymin = true;
			if (src.cols / 7*6 < pi.x)xmax = true;
			if (src.rows / 8*7 < pi.y)ymax = true;
		}
		if (xmin && ymin && xmax && ymax)break;
	}
	contoursNum++;
}

这对于一些场景有帮助,但是对于最外面的干扰轮廓很清晰的情况,还是无法避免。

6,坐标微调

计算的坐标还是容易受最外面的轮廓的影响,所以我们把坐标进行微调。

试了几个方法都不太好,先不做这个了,留一个接口,如果需要的话可以手动调。

void GetPos()
{
	xmin += 0, ymin += 0; // 手动调整
	return;
}

7,手动删减轮廓

最外面的轮廓干扰太大,所以最后我干脆提供一个手动删掉几个轮廓的接口。

void RemoveContours(vector<std::vector<Point>>& contours)
{
	int id[] = { 2,3 }; // 手动调整
	for (int i = sizeof(id) / sizeof(int); i >= 0; i--) {
		if (id[i] < contours.size())contours.erase(contours.begin() + id[i]);
	}
}

手动调坐标不太好操作,而且不精确,但根据显示的图很容易找出最外面的1-2个轮廓(如果有的话),这样就可以直接手动填写要删除的轮廓id重新运行。

8,解析空出来的3个格子

void GetInvalidPos(int size, Mat src)
{
	int x[8][7];
	int m, d, w, k = 0;
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++) {
		x[i][j] = 0;
		if (i < 2 && j == 6)continue;
		if (i == 7 && j < 4)continue;
		int r = ymin + size * i;
		int c = xmin + size * j;
		for (int row = r + size / 4; row < r + size / 4 * 3; row++) {
			for (int col = c + size / 4; col < c + size / 4 * 3; col++) {
				x[i][j] += int(src.at<uchar>(row, col));
			}
		}
		if (x[i][j] > 100) {
			if (k == 0) {
				m = i * 6 + j + 1; // 1-12
			} else if (k == 1) {
				d = (i - 2) * 7 + j + 1; // 1-31
			} else {
				w = (i - 6) * 3 + j - 3; // 0-6
			}
			k++;
		}
	}
	string s[] = { "日","一","二" ,"三" ,"四" ,"五" ,"六" };
	cout << m << "月" << d << "日周" << s[w];
}

8,连通性计算

void connect(Mat src)
{

	//for (int i = 0; i < src.rows; i++)for (int j = 0; j < src.cols; j++) {
	//	if (i%size_ == ymin % size_ || j % size_ == xmin % size_) {
	//		src.at<uchar>(i,j) = 200;
	//	}
	//}
	//imshow("src", src);

	bool up[8][7];
	for (int i = 1; i < 8; i++)for (int j = 0; j < 7; j++) {
		up[i][j] = true;
		if (!valid(i,j))continue;
		if (!valid(i-1, j))continue;
		int s = 0;
		//src.at<uchar>(ymin + size_ * i - size_ / 4, xmin + size_ * j + size_ / 4) = 200;
		//src.at<uchar>(ymin + size_ * i + size_ / 4, xmin + size_ * j + size_ / 4 * 3) = 200;
		for (int r = ymin + size_ * i - size_ / 4; r < ymin + size_ * i + size_ / 4; r++) {
			for (int c = xmin + size_ * j + size_ / 4; c < xmin + size_ * j + size_ / 4 * 3; c++) {
				if (int(src.at<uchar>(r, c)) > 10)s++;
			}
		}
		if (s > 5)up[i][j] = false;
	}
	//imshow("src", src);
	bool left[8][7];
	for (int i = 0; i < 8; i++)for (int j = 1; j < 7; j++) {
		left[i][j] = true;
		if (!valid(i, j))continue;
		if (!valid(i, j-1))continue;
		int s = 0;
		for (int r = ymin + size_ * i + size_ / 4; r < ymin + size_ * i + size_ / 4*3; r++) {
			for (int c = xmin + size_ * j - size_ / 4; c < xmin + size_ * j + size_ / 4; c++) {
				if (int(src.at<uchar>(r, c)) > 10)s++;
			}
		}
		if (s > 10)left[i][j] = false;
	}
	return;
}

计算每2个格子间的交接处有没有边缘检测出的点,判断2个格子是否连通。

再用并查集把连通的格子连起来。

bool valid2(int i, int j)
{
	if (!valid(i,j))return false;
	if (i == mi && j == mj)return false;
	if (i == di && j == dj)return false;
	if (i == wi && j == wj)return false;
	return true;
}
int fa[8 * 7]; // id=i*7+j
int find(int x)	//找祖先
{
	if (fa[x] == x)return x;
	return fa[x] = find(fa[x]);
}
void split()
{
	for (int i = 0; i < 56; i++)fa[i] = i;
	for (int i = 1; i < 8; i++)for (int j = 0; j < 7; j++) {
		if (!valid2(i, j))continue;
		if (!valid2(i - 1, j))continue;
		if (up[i][j])fa[find(i * 7 + j)] = find((i - 1) * 7 + j);
	}
	for (int i = 0; i < 8; i++)for (int j = 1; j < 7; j++) {
		if (!valid2(i, j))continue;
		if (!valid2(i, j-1))continue;
		if (left_[i][j])fa[find(i * 7 + j)] = find(i * 7 + j - 1);
	}
	map<int, int>m;
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++) {
		if (!valid2(i, j))continue;
		m[find(i * 7 + j)]++;
	}
	int k = 0;
	map<int, int>m2;
	for (auto &mi : m)m2[mi.first] = ++k;
	int block[8][7];
	for (int i = 0; i < 8; i++) {
		for (int j = 0; j < 7; j++) {
			if (!valid2(i, j))block[i][j] = 0;
			else block[i][j] = m2[find(i * 7 + j)];
			cout <<setw(3)<< block[i][j];
		}
		cout << endl;
	}
	return;
}

9,完整代码



#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<map>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/core/mat.hpp>
using namespace std;
using namespace cv;


#pragma comment(lib,"../x64/vc14/lib/opencv_world452.lib")
#pragma comment(lib,"../x64/vc14/lib/opencv_world452d.lib")



int xmin, ymin, size_;
int contoursNum;
bool up[8][7];
bool left_[8][7];
int mi, mj, di, dj, wi, wj;

template<typename T>
bool cmp(vector<T> x, vector<T> y)
{
	return x.size() > y.size();
}

Mat GetImage(int i)
{
	Mat img = imread("D:/p/img (" + to_string(i) + ").jpg", 0);
	resize(img, img, Size(0, 0), 0.3, 0.3);
	Mat src;
	threshold(img, src, 200, 255, THRESH_TRUNC);
	threshold(src, src, 100, 255, THRESH_TOZERO);
	return src;
}
void RemoveContours(vector<std::vector<Point>>& contours)
{
	int id[] = { 100 }; // 手动调整
	for (int i = sizeof(id) / sizeof(int) -1; i >= 0; i--) {
		if (id[i] < contours.size())contours.erase(contours.begin() + id[i]);
	}
}
void GetContoursNum(Mat src, const vector<std::vector<Point>>& contours)
{
	bool xmin = false, xmax = false, ymin = false, ymax = false;
	contoursNum = 0;
	for (contoursNum = 0; contoursNum < contours.size(); contoursNum++) {
		for (auto& pi : contours[contoursNum]) {
			if (src.cols / 7 > pi.x)xmin = true;
			if (src.rows / 8 > pi.y)ymin = true;
			if (src.cols / 7 * 6 < pi.x)xmax = true;
			if (src.rows / 8 * 7 < pi.y)ymax = true;
		}
		if (xmin && ymin && xmax && ymax)break;
	}
	contoursNum++;
}
void GetSize(const vector<std::vector<Point>>& contours)
{
	xmin = 1234567, ymin = 1234567;
	int xmax = 0, ymax = 0;
	for (int i = 0; i < contoursNum && i < contours.size(); i++) {
		for (auto& pi : contours[i]) {
			if (xmin > pi.x)xmin = pi.x;
			if (ymin > pi.y)ymin = pi.y;
			if (xmax < pi.x)xmax = pi.x;
			if (ymax < pi.y)ymax = pi.y;
		}
	}
	int dx = xmax - xmin, dy = ymax - ymin;
	dx /= 7, dy /= 8;
	//cout << endl << dx << endl << dy;
	size_ = dx;
}

void GetPos()
{
	xmin += 0, ymin += 0; // 手动调整
	return;
}

bool valid(int i, int j)
{
	if (i < 2 && j == 6)return false;
	if (i == 7 && j < 4)return false;
	return true;
}

void GetInvalidPos(Mat src)
{
	int x[8][7];
	int m, d, w, k = 0;
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++) {
		x[i][j] = 0;
		if (!valid(i, j))continue;
		int r = ymin + size_ * i;
		int c = xmin + size_ * j;
		for (int row = r + size_ / 4; row < r + size_ / 4 * 3; row++) {
			for (int col = c + size_ / 4; col < c + size_ / 4 * 3; col++) {
				x[i][j] += int(src.at<uchar>(row, col));
			}
		}
		if (x[i][j] > 2000) {
			if (k == 0) {
				mi = i, mj = j;
				m = i * 6 + j + 1; // 1-12
			}
			else if (k == 1) {
				di = i, dj = j;
				d = (i - 2) * 7 + j + 1; // 1-31
			}
			else {
				wi = i, wj = j;
				w = (i - 6) * 3 + j - 3; // 0-6
			}
			k++;
		}
	}
	if (w < 0 || w>7) {
		cout << "error,w=" << w << endl;
		w = 0;
	}
	string s[] = { "日","一","二" ,"三" ,"四" ,"五" ,"六" };
	cout << m << "月" << d << "日周" << s[w] << endl;
}

void connect(Mat src)
{

	//for (int i = 0; i < src.rows; i++)for (int j = 0; j < src.cols; j++) {
	//	if (i%size_ == ymin % size_ || j % size_ == xmin % size_) {
	//		src.at<uchar>(i,j) = 200;
	//	}
	//}
	//imshow("src", src);


	for (int i = 1; i < 8; i++)for (int j = 0; j < 7; j++) {
		up[i][j] = true;
		if (!valid(i, j))continue;
		if (!valid(i - 1, j))continue;
		int s = 0;
		//src.at<uchar>(ymin + size_ * i - size_ / 4, xmin + size_ * j + size_ / 4) = 200;
		//src.at<uchar>(ymin + size_ * i + size_ / 4, xmin + size_ * j + size_ / 4 * 3) = 200;
		for (int r = ymin + size_ * i - size_ / 4; r < ymin + size_ * i + size_ / 4; r++) {
			for (int c = xmin + size_ * j + size_ / 4; c < xmin + size_ * j + size_ / 4 * 3; c++) {
				if (int(src.at<uchar>(r, c)) > 10)s++;
			}
		}
		if (s > 5)up[i][j] = false;
	}
	//imshow("src", src);

	for (int i = 0; i < 8; i++)for (int j = 1; j < 7; j++) {
		left_[i][j] = true;
		if (!valid(i, j))continue;
		if (!valid(i, j - 1))continue;
		int s = 0;
		for (int r = ymin + size_ * i + size_ / 4; r < ymin + size_ * i + size_ / 4 * 3; r++) {
			for (int c = xmin + size_ * j - size_ / 4; c < xmin + size_ * j + size_ / 4; c++) {
				if (int(src.at<uchar>(r, c)) > 10)s++;
			}
		}
		if (s > 10)left_[i][j] = false;
	}
	return;
}

bool valid2(int i, int j)
{
	if (!valid(i, j))return false;
	if (i == mi && j == mj)return false;
	if (i == di && j == dj)return false;
	if (i == wi && j == wj)return false;
	return true;
}
int fa[8 * 7]; // id=i*7+j
int find(int x)	//找祖先
{
	if (fa[x] == x)return x;
	return fa[x] = find(fa[x]);
}
void split()
{
	for (int i = 0; i < 56; i++)fa[i] = i;
	for (int i = 1; i < 8; i++)for (int j = 0; j < 7; j++) {
		if (!valid2(i, j))continue;
		if (!valid2(i - 1, j))continue;
		if (up[i][j])fa[find(i * 7 + j)] = find((i - 1) * 7 + j);
	}
	for (int i = 0; i < 8; i++)for (int j = 1; j < 7; j++) {
		if (!valid2(i, j))continue;
		if (!valid2(i, j - 1))continue;
		if (left_[i][j])fa[find(i * 7 + j)] = find(i * 7 + j - 1);
	}
	map<int, int>m;
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++) {
		if (!valid2(i, j))continue;
		m[find(i * 7 + j)]++;
	}
	using P = pair<int, int>;
	vector<P>v;
	for (auto& mi : m)v.push_back(mi);
	sort(v.begin(), v.end(), [](P p1, P p2) { return p1.second > p2.second; });
	int k = 0;
	map<int, int>m2;
	for (auto& vi : v)m2[vi.first] = ++k;
	int block[8][7];
	int pix = 50;
	Mat img = Mat(Size(pix * 7, pix * 8), CV_8UC1);
	for (int i = 0; i < 8; i++) {
		for (int j = 0; j < 7; j++) {
			if (!valid2(i, j))block[i][j] = 0;
			else block[i][j] = m2[find(i * 7 + j)];
			cout << setw(3) << block[i][j];
			for (int r = pix * i; r < pix * (i + 1); r++) {
				for (int c = pix * j; c < pix * (j + 1); c++) {
					img.at<uchar>(r, c) = 25 * block[i][j];
				}
			}
			if (!valid2(i, j)) {
				for (int x = 0; x < pix; x++) {
					img.at<uchar>(pix * i + x, pix * j + x) = 255;
					img.at<uchar>(pix * i + x, pix * j + pix - x -1) = 255;
				}
			}
		}
		cout << endl;
	}
	static int kid = 0;
	imshow("ans"+to_string(kid++),img);
	return;
}

void f(int i)
{
	Mat src = GetImage(i);
	Canny(src, src, 200, 100, 3);
	//cv::imshow("src" + to_string(i), src);

	std::vector<std::vector<Point>> contours;
	std::vector<Vec4i> hierarchy;
	findContours(src, contours, hierarchy, RETR_LIST, CHAIN_APPROX_NONE, Point(0, 0));
	//cout << contours.size() << endl;
	sort(contours.begin(), contours.end(), cmp< Point>);
	RemoveContours(contours);
	//for (int i = 0; i < contours.size(); i++)cout << contours[i].size() << " ";
	GetContoursNum(src, contours);

	Mat img(Size(src.cols, src.rows), src.type());
	img = 0;
	for (int i = 0; i < contoursNum && i < contours.size(); i++) {
		cv::drawContours(img, contours, i, cv::Scalar::all(255));
		//cv::imshow("contours" + to_string(i), img);
	}

	GetSize(contours);
	GetPos();
	GetInvalidPos(src);
	connect(src);
	split();
}

int main()
{
	for (int i = 7; i <= 11; i++)
	{
		f(i);
	}
	cv::waitKey(0);
	return 0;
}

运行效果:

可以看到数字化完全正确,为了方便校验做出来的灰度图也一致。

在10张照片里面有一张运行有点问题:

有2个块连起来了,这种情况只能手动微改一下了。

六,以解生解

每完成一个月的解法,就可以按照大拇指和U型分别生成解,把找到的新解存下来以作备用。

1,大拇指

把形似大拇指的这个块,通过翻转,可以生成不同的解。

(1)识别大拇指 

//#include "data.h"

#include<iostream>
#include <vector>
using namespace std;

#define OUT(x) cout << endl << #x << " = "; Print(x);
template<typename T>
inline void Print(T x)
{
	cout << x << " ";
}
template<typename T>
inline void Read(T& x)
{
	while (!(cin >> x)) { // only cin type T, ignore other info
		cin.clear();
		cin.ignore();
	}
}

const float theNan = 0.123456; //float默认只有6位
void Print(float x)
{
	if (std::isnan(x)) cout << theNan << " ";
	else cout << x << " ";
}
void Read(float& x)
{
	Read<float>(x);
	if (x == theNan) x = NAN;
}

int main()
{
	int x[8][7];
	while (true)
	{
		for (int i = 0; i < 8; i++)
		{
			for (int j = 0; j < 7; j++)
			{
				Read(x[i][j]);
			}
		}
		for (int k = 1; k < 10; k++)
		{
			int xmin = 10, ymin = 10, xmax = 0, ymax = 0;
			for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)
			{
				if (x[i][j] != k)continue;
				xmin = min(xmin, i);
				ymin = min(ymin, j);
				xmax = max(xmax, i);
				ymax = max(ymax, j);
			}
			if ((xmax - xmin + 1) * (ymax - ymin + 1) != 6)continue;
			bool flag = true;
			int n = 0;
			for (int i = xmin; i <= xmax && flag; i++)for (int j = ymin; j <= ymax && flag; j++)
			{
				if (x[i][j] == k)continue;
				if (x[i][j])flag = false;
				n++;
			}
			if (!flag || n > 1)continue;
			if (x[xmin][ymin] && x[xmin][ymax] && x[xmax][ymin] && x[xmax][ymax])continue;
			cout << "                                  "<<k << endl;
		}
	}
	return 0;
}

(2)进行翻转

除了当前解,还可以生成3个不同的解

            for (int i = 0; i < 3; i++) {
				int tmp = x[xmin][ymin];
				x[xmin][ymin] = x[xmin][ymax];
				x[xmin][ymax] = x[xmax][ymin];
				x[xmax][ymin] = x[xmax][ymax];
				x[xmax][ymax] = tmp;

			}

(3)校验是否合法

int x[8][7];
int m, d, w;
string s[] = { "日","一","二" ,"三" ,"四" ,"五" ,"六" };
bool valid(int i, int j)
{
	if (i < 2 && j == 6)return false;
	if (i == 7 && j < 4)return false;
	return true;
}
bool check()
{
	int k = 0;
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++) {
		if (!valid(i, j))continue;
		if (x[i][j] == 0) {
			if (k == 0) {
				if (i > 1)
					return false;
				m = i * 6 + j + 1; // 1-12
			}
			else if (k == 1) {
				if (i <= 1)
					return false;
				if (i * 7 + j >= 45)
					return false;
				d = (i - 2) * 7 + j + 1; // 1-31
			}
			else {
				if (i * 7 + j < 45)
					return false;
				w = (i - 6) * 3 + j - 3; // 0-6
			}
			k++;
		}
	}
}

2,可视化

为了方便查看,单独把显示图像的函数提取出来。

int x[8][7];

void show()
{
	int pix = 50;
	Mat img = Mat(Size(pix * 7, pix * 8), CV_8UC1);
	for (int i = 0; i < 8; i++) {
		for (int j = 0; j < 7; j++) {
			for (int r = pix * i; r < pix * (i + 1); r++) {
				for (int c = pix * j; c < pix * (j + 1); c++) {
					img.at<uchar>(r, c) = 25 * x[i][j];
				}
			}
			if (x[i][j]==0) {
				for (int x = 0; x < pix; x++) {
					img.at<uchar>(pix * i + x, pix * j + x) = 255;
					img.at<uchar>(pix * i + x, pix * j + pix - x - 1) = 255;
				}
			}
		}
		cout << endl;
	}
	static int kid = 0;
	imshow("ans" + to_string(kid++), img);
}

int main()
{
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)Read(x[i][j]);
	show();
	cv::waitKey(0);
	return 0;
}

3,U型

和大拇指类似,U型也可以用来生成解。

代码几乎是一样的,微改一下即可:

int main()
{
	freopen("D:/out.txt", "w", stdout);
	while (true)
	{
		for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)Read(x[i][j]);
		for (int k = 1; k < 10; k++)
		{
			int xmin = 10, ymin = 10, xmax = 0, ymax = 0;
			for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)
			{
				if (x[i][j] != k)continue;
				xmin = min(xmin, i);
				ymin = min(ymin, j);
				xmax = max(xmax, i);
				ymax = max(ymax, j);
			}
			if ((xmax - xmin + 1) * (ymax - ymin + 1) != 6)continue;
			bool flag = true;
			int n = 0;
			for (int i = xmin; i <= xmax && flag; i++)for (int j = ymin; j <= ymax && flag; j++)
			{
				if (x[i][j] == k)continue;
				if (x[i][j])flag = false;
				n++;
			}
			if (!flag || n > 1)continue;
			if (!(x[xmin][ymin] && x[xmin][ymax] && x[xmax][ymin] && x[xmax][ymax]))continue;
			//cout << "                                  "<<k << endl;
			int tmp = x[(xmin + xmax) / 2][(ymin + ymax) / 2];
			x[(xmin + xmax) / 2][(ymin + ymax) / 2] = x[xmin + 1][ymin + 1], x[xmin + 1][ymin + 1] = tmp;
			if (check()) {
				cout << m << "月" << d << "日周" << s[w] << endl;
				for (int i = 0; i < 8; i++) {
					for (int j = 0; j < 7; j++) {
						cout << setw(3) << x[i][j];
					}
					cout << endl;
				}
			}
			break;
		}
	}
	return 0;
}

4,新解

由于产生的新解太多,所以挪到本地磁盘了。

5,日期汇总

为了自动去重,建立日期汇总,每次有一个解产生时,都把日期加进来。以本地文件为准。

6,完整代码V1

//#include "data.h"

#include <iostream>
#include <vector>
#include <iomanip>
#include <map>
#include <string>
using namespace std;

#define OUT(x) cout << endl << #x << " = "; Print(x);
template<typename T>
inline void Print(T x)
{
	cout << x << " ";
}
template<typename T>
inline void Read(T& x)
{
	while (!(cin >> x)) { // only cin type T, ignore other info
		cin.clear();
		cin.ignore();
	}
}

const float theNan = 0.123456; //float默认只有6位
void Print(float x)
{
	if (std::isnan(x)) cout << theNan << " ";
	else cout << x << " ";
}
void Read(float& x)
{
	Read<float>(x);
	if (x == theNan) x = NAN;
}

int x[8][7];
int m, d, w;
string s[] = { "日","一","二" ,"三" ,"四" ,"五" ,"六" };
bool valid(int i, int j)
{
	if (i < 2 && j == 6)return false;
	if (i == 7 && j < 4)return false;
	return true;
}
bool check()
{
	int k = 0;
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++) {
		if (!valid(i, j))continue;
		if (x[i][j] == 0) {
			if (k == 0) {
				if (i > 1)
					return false;
				m = i * 6 + j + 1; // 1-12
			}
			else if (k == 1) {
				if (i <= 1)
					return false;
				if (i * 7 + j >= 45)
					return false;
				d = (i - 2) * 7 + j + 1; // 1-31
			}
			else {
				if (i * 7 + j < 45)
					return false;
				w = (i - 6) * 3 + j - 3; // 0-6
			}
			k++;
		}
	}
}

int main()
{
	freopen("D:/p/date.txt", "r", stdin);
	string s1;
	map<string, int>sm;
	while (cin >> s1)sm[s1] = 1;
	freopen("CON", "r", stdin);
	while (true)
	{
		for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)Read(x[i][j]);
		for (int k = 1; k < 10; k++)
		{
			int xmin = 10, ymin = 10, xmax = 0, ymax = 0;
			for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)
			{
				if (x[i][j] != k)continue;
				xmin = min(xmin, i);
				ymin = min(ymin, j);
				xmax = max(xmax, i);
				ymax = max(ymax, j);
			}
			if ((xmax - xmin + 1) * (ymax - ymin + 1) != 6)continue;
			bool flag = true;
			int n = 0;
			for (int i = xmin; i <= xmax && flag; i++)for (int j = ymin; j <= ymax && flag; j++)
			{
				if (x[i][j] == k)continue;
				if (x[i][j])flag = false;
				n++;
			}
			if (!flag || n > 1)continue;
			if (!(x[xmin][ymin] && x[xmin][ymax] && x[xmax][ymin] && x[xmax][ymax])) {
				for (int i = 0; i < 4; i++) {
					int tmp = x[xmin][ymin];
					x[xmin][ymin] = x[xmin][ymax];
					x[xmin][ymax] = x[xmax][ymin];
					x[xmax][ymin] = x[xmax][ymax];
					x[xmax][ymax] = tmp;
					
					if (check()) {
						string ts = to_string(m) + "月" + to_string(d) + "日周" + s[w];
						if (sm[ts])continue;
						sm[ts] = 1;
						cout << ts << endl;
						for (int i = 0; i < 8; i++) {
							for (int j = 0; j < 7; j++) {
								cout << setw(3) << x[i][j];
							}
							cout << endl;
						}
					}
				}
			}
			else {
				int tmp = x[(xmin + xmax) / 2][(ymin + ymax) / 2];
				x[(xmin + xmax) / 2][(ymin + ymax) / 2] = x[xmin + 1][ymin + 1], x[xmin + 1][ymin + 1] = tmp;
				if (check()) {
					string ts = to_string(m) + "月" + to_string(d) + "日周" + s[w];
					if (sm[ts])continue;
					sm[ts] = 1;
					cout << ts << endl;
					for (int i = 0; i < 8; i++) {
						for (int j = 0; j < 7; j++) {
							cout << setw(3) << x[i][j];
						}
						cout << endl;
					}
				}
			}
		}
	}
	return 0;
}

7,BUG修复

如果同时存在大拇指和U型新解,那么上面的代码只能产生一部分新解。

由于这个代码已经运行一个月,目前一共已经得到400种不同的解法,所以解决方法最好还要能修复之前缺失的新解。

所以我把控制台输入改成从文件输入,把历史所有解当做输入,清算有没有漏的。

再修复一个BUG,之前的代码遗漏了数字为10的块也可以以解生解。

代码略,参见下一节。

8,日期优化(完整代码V2)

记录日期的文件除了被程序读取使用外,还被我肉眼读,因为我经常手动以解生解,需要查看哪些日期还没有解。

日期逐渐多了之后,不太好看了,所以我优化了数据结构,以“-1月1日”表示1月1日的从周一到周日的七个组合都有解了。

代码只需要把读取日期记录文件的地方略改即可。

完整代码:

#include "data.h"

#include <iostream>
#include <vector>
#include <iomanip>
#include <map>
#include <string>
using namespace std;

#define OUT(x) cout << endl << #x << " = "; Print(x);
template<typename T>
inline void Print(T x)
{
	cout << x << " ";
}
template<typename T>
inline void Read(T& x)
{
	while (!(cin >> x)) { // only cin type T, ignore other info
		cin.clear();
		cin.ignore();
	}
}

const float theNan = 0.123456; //float默认只有6位
void Print(float x)
{
	if (std::isnan(x)) cout << theNan << " ";
	else cout << x << " ";
}
void Read(float& x)
{
	Read<float>(x);
	if (x == theNan) x = NAN;
}

int x[8][7];
int m, d, w;
string s[] = { "日","一","二" ,"三" ,"四" ,"五" ,"六" };
bool valid(int i, int j)
{
	if (i < 2 && j == 6)return false;
	if (i == 7 && j < 4)return false;
	return true;
}
bool check()
{
	int k = 0;
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++) {
		if (!valid(i, j))continue;
		if (x[i][j] == 0) {
			if (k == 0) {
				if (i > 1)
					return false;
				m = i * 6 + j + 1; // 1-12
			}
			else if (k == 1) {
				if (i <= 1)
					return false;
				if (i * 7 + j >= 45)
					return false;
				d = (i - 2) * 7 + j + 1; // 1-31
			}
			else {
				if (i * 7 + j < 45)
					return false;
				w = (i - 6) * 3 + j - 3; // 0-6
			}
			k++;
		}
	}
	if (m == 2 && d > 29)return false;
	if ((m == 4 || m == 6 || m == 9 || m == 11) && d > 30)return false;
	return true;
}

void go()
{
	freopen("D:/p/date.txt", "r", stdin);
	string s1;
	map<string, int>sm;
	while (cin >> s1) {
		sm[s1] = 1;
		if (s1[0] == '-') {
			s1 = s1.substr(1, s1.length() - 1);
			for (int i = 0; i < 7; i++)sm[s1 + "周" + s[i]] = 1;
		}
	}
	freopen("D:/p/ans.txt", "r", stdin);
	while (true)
	{
		int a, b;
		Read(a); Read(b);
		for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)Read(x[i][j]);
		for (int k = 1; k <= 10; k++)
		{
			int xmin = 10, ymin = 10, xmax = 0, ymax = 0;
			for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)
			{
				if (x[i][j] != k)continue;
				xmin = min(xmin, i);
				ymin = min(ymin, j);
				xmax = max(xmax, i);
				ymax = max(ymax, j);
			}
			if ((xmax - xmin + 1) * (ymax - ymin + 1) != 6)continue;
			bool flag = true;
			int n = 0;
			for (int i = xmin; i <= xmax && flag; i++)for (int j = ymin; j <= ymax && flag; j++)
			{
				if (x[i][j] == k)continue;
				if (x[i][j])flag = false;
				n++;
			}
			if (!flag || n > 1)continue;
			if (!(x[xmin][ymin] && x[xmin][ymax] && x[xmax][ymin] && x[xmax][ymax])) {
				for (int i = 0; i < 4; i++) {
					int tmp = x[xmin][ymin];
					x[xmin][ymin] = x[xmin][ymax];
					x[xmin][ymax] = x[xmax][ymin];
					x[xmax][ymin] = x[xmax][ymax];
					x[xmax][ymax] = tmp;
					if (check()) {
						string ts = to_string(m) + "月" + to_string(d) + "日周" + s[w];
						if (sm[ts])continue;
						sm[ts] = 1;
						cout << ts << endl;
						for (int i = 0; i < 8; i++) {
							for (int j = 0; j < 7; j++) {
								cout << setw(3) << x[i][j];
							}
							cout << endl;
						}
					}
				}
			}
			else {
				int tmp = x[(xmin + xmax) / 2][(ymin + ymax) / 2];
				x[(xmin + xmax) / 2][(ymin + ymax) / 2] = x[xmin + 1][ymin + 1], x[xmin + 1][ymin + 1] = tmp;
				if (check()) {
					string ts = to_string(m) + "月" + to_string(d) + "日周" + s[w];
					if (sm[ts])continue;
					sm[ts] = 1;
					cout << ts << endl;
					for (int i = 0; i < 8; i++) {
						for (int j = 0; j < 7; j++) {
							cout << setw(3) << x[i][j];
						}
						cout << endl;
					}
				}
			}
		}
	}
}

int main()
{
	go();
	return 0;
}

9,BUG修复、新增检查(完整代码V3)

经过了前面的BUG修复之后,仍然存在以解生解不全的问题。

所以我又把2种以解生解的模式做了拆分,先做U型再做大拇指,分开成2次编译运行,先只调用go后只调用go1,这样才能确保生成所有的解。

然后新增了go2和go3,需要检查的时候调用即可。

完整代码:

#include<iostream>
using namespace std;

#define OUT(x) cout << endl << #x << " = "; Print(x);
template<typename T>
inline void Print(T x)
{
	cout << x << " ";
}
template<typename T>
inline void Read(T& x)
{
	while (!(cin >> x)) { // only cin type T, ignore other info
		cin.clear();
		cin.ignore();
	}
}

const float theNan = 0.123456; //float默认只有6位
void Print(float x)
{
	if (std::isnan(x)) cout << theNan << " ";
	else cout << x << " ";
}
void Read(float& x)
{
	Read<float>(x);
	if (x == theNan) x = NAN;
}
template<typename T1, typename T2>
inline void Print(const std::pair<T1, T2>& p)
{
	Print(p.first);
	Print(p.second);
}
template<typename T1, typename T2>
inline void Print(const map<T1, T2>& aMap)
{
	cout << " size = " << aMap.size() << endl;
	for (auto& it : aMap) {
		Print(it);
		cout << endl;
	}
}
template<typename T>
inline void Print(const vector<T>& vec)
{
	cout << " size = " << vec.size() << endl;
	for (auto& it : vec) {
		Print(it);
	}
}
template<typename T1, typename T2>
inline void Read(std::pair<T1, T2>& p)
{
	Read(p.first);
	Read(p.second);
}
template<typename Tkey, typename Tvalue>
void Read(std::map<Tkey, Tvalue>& aMap)
{
	int num;
	Read(num);
	std::pair<Tkey, Tvalue> p;
	while (num--) {
		Read(p);
		aMap[p.first] = p.second;
	}
}
template<typename T>
inline void Read(vector<T>& vec)
{
	int num;
	Read(num);
	vec.resize(num); // 慎用
	for (int i = 0; i < num; i++) {
		Read(vec[i]);
	}
}

int x[8][7];
int m, d, w;
string s[] = { "日","一","二" ,"三" ,"四" ,"五" ,"六" };
bool valid(int i, int j)
{
	if (i < 2 && j == 6)return false;
	if (i == 7 && j < 4)return false;
	return true;
}
bool check()
{
	int k = 0;
	for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++) {
		if (!valid(i, j))continue;
		if (x[i][j] == 0) {
			if (k == 0) {
				if (i > 1)
					return false;
				m = i * 6 + j + 1; // 1-12
			}
			else if (k == 1) {
				if (i <= 1)
					return false;
				if (i * 7 + j >= 45)
					return false;
				d = (i - 2) * 7 + j + 1; // 1-31
			}
			else {
				if (i * 7 + j < 45)
					return false;
				w = (i - 6) * 3 + j - 3; // 0-6
			}
			k++;
		}
	}
	if (m == 2 && d > 29)return false;
	if ((m == 4 || m == 6 || m == 9 || m == 11) && d > 30)return false;
	return true;
}

void go() //以解生解
{
	freopen("D:/p/date.txt", "r", stdin);
	string s1;
	map<string, int>sm;
	while (cin >> s1) {
		sm[s1] = 1;
		if (s1[0] == '-') {
			s1 = s1.substr(1, s1.length() - 1);
			for (int i = 0; i < 7; i++)sm[s1 + "周" + s[i]] = 1;
		}
	}
	freopen("D:/p/ans.txt", "r", stdin);
	while (true)
	{
		int a, b;
		Read(a); Read(b);
		for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)Read(x[i][j]);
		for (int k = 1; k <= 10; k++)
		{
			int xmin = 10, ymin = 10, xmax = 0, ymax = 0;
			for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)
			{
				if (x[i][j] != k)continue;
				xmin = min(xmin, i);
				ymin = min(ymin, j);
				xmax = max(xmax, i);
				ymax = max(ymax, j);
			}
			if ((xmax - xmin + 1) * (ymax - ymin + 1) != 6)continue;
			bool flag = true;
			int n = 0;
			for (int i = xmin; i <= xmax && flag; i++)for (int j = ymin; j <= ymax && flag; j++)
			{
				if (x[i][j] == k)continue;
				if (x[i][j])flag = false;
				n++;
			}
			if (!flag || n > 1)continue;
			if (x[xmin][ymin] && x[xmin][ymax] && x[xmax][ymin] && x[xmax][ymax]) // U型
			{ 
				int tmp = x[(xmin + xmax) / 2][(ymin + ymax) / 2];
				x[(xmin + xmax) / 2][(ymin + ymax) / 2] = x[xmin + 1][ymin + 1], x[xmin + 1][ymin + 1] = tmp;
				if (check()) {
					string ts = to_string(m) + "月" + to_string(d) + "日周" + s[w];
					if (sm[ts])continue;
					sm[ts] = 1;
					cout << ts << endl;
					for (int i = 0; i < 8; i++) {
						for (int j = 0; j < 7; j++) {
							cout << setw(3) << x[i][j];
						}
						cout << endl;
					}
				}
			}
		}
	}
}
void go1() //以解生解
{
	freopen("D:/p/date.txt", "r", stdin);
	string s1;
	map<string, int>sm;
	while (cin >> s1) {
		sm[s1] = 1;
		if (s1[0] == '-') {
			s1 = s1.substr(1, s1.length() - 1);
			for (int i = 0; i < 7; i++)sm[s1 + "周" + s[i]] = 1;
		}
	}
	freopen("D:/p/ans.txt", "r", stdin);
	while (true)
	{
		int a, b;
		Read(a); Read(b);
		for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)Read(x[i][j]);
		for (int k = 1; k <= 10; k++)
		{
			int xmin = 10, ymin = 10, xmax = 0, ymax = 0;
			for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)
			{
				if (x[i][j] != k)continue;
				xmin = min(xmin, i);
				ymin = min(ymin, j);
				xmax = max(xmax, i);
				ymax = max(ymax, j);
			}
			if ((xmax - xmin + 1) * (ymax - ymin + 1) != 6)continue;
			bool flag = true;
			int n = 0;
			for (int i = xmin; i <= xmax && flag; i++)for (int j = ymin; j <= ymax && flag; j++)
			{
				if (x[i][j] == k)continue;
				if (x[i][j])flag = false;
				n++;
			}
			if (!flag || n > 1)continue;
			if (!(x[xmin][ymin] && x[xmin][ymax] && x[xmax][ymin] && x[xmax][ymax])) //大拇指
			{
				for (int i = 0; i < 4; i++) {
					int tmp = x[xmin][ymin];
					x[xmin][ymin] = x[xmin][ymax];
					x[xmin][ymax] = x[xmax][ymin];
					x[xmax][ymin] = x[xmax][ymax];
					x[xmax][ymax] = tmp;
					if (check()) {
						string ts = to_string(m) + "月" + to_string(d) + "日周" + s[w];
						if (sm[ts])continue;
						sm[ts] = 1;
						cout << ts << endl;
						for (int i = 0; i < 8; i++) {
							for (int j = 0; j < 7; j++) {
								cout << setw(3) << x[i][j];
							}
							cout << endl;
						}
					}
				}
			}
		}
	}
}

void go2()//检查日期记录有没有漏的
{
	string s1;
	map<string, int>sm;
	freopen("D:/p/date.txt", "r", stdin);
	while (cin >> s1) {
		sm[s1] = 1;
		if (s1[0] == '-') {
			s1 = s1.substr(1, s1.length() - 1);
			for (int i = 0; i < 7; i++)sm[s1 + "周" + s[i]] = 1;
		}
	}
	cin.clear();
	freopen("CON", "r", stdin);
	freopen("D/p/out.txt", "w", stdout);
	while (cin >> s1)
	{
		for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)Read(x[i][j]);
		if (sm[s1] == 0)cout << s1 << endl;
	}
}
void go3()//检查有没有重复日期的解
{
	string s1;
	map<string, int>sm;
	freopen("D/p/out.txt", "w", stdout);
	while (cin >> s1)
	{
		for (int i = 0; i < 8; i++)for (int j = 0; j < 7; j++)Read(x[i][j]);
		if (sm[s1] == 1)cout << s1 << endl;
		sm[s1] = 1;
	}
}



int main()
{
    //go();
	go1();
	return 0;
}

七,说明

1,每天可以在本文搜索一下,如果已经有解了就不用再拼了。否则,新拼出一个解时,把照片放到本地,等每隔一段时间再统一数字化。

2,数字化时,通过批量命名把所有图片改成img*.jpg,然后运行第五章第9节的完整代码,把图片转化成数字。

3,把数字化的结果更新到(本地)结果汇总中,把其中的日期,更新到(本地)日期汇总中。

4,运行第六章第7节的完整代码V2,产生新解,跳到第3步,循环,直到再也没有新解。

5,如果想查看一个数字化的解,可以运行上面第六章第2节的代码,也可以运行下面的可视化V2版。

八,直接求解

1,可视化V2版

对显示答案做了微调,把月日周对应的3个格子用真实的内容显示出来。

int x[8][7];

void show()
{
	int pix = 50;
	Mat img = imread("D:/base.jpg",0);
	resize(img, img, Size(pix * 7, pix * 8), 0, 0);
	for (int i = 0; i < 8; i++) {
		for (int j = 0; j < 7; j++) {
			if(x[i][j])for (int r = pix * i; r < pix * (i + 1); r++) {
				for (int c = pix * j; c < pix * (j + 1); c++) {
					img.at<uchar>(r, c) = 25 * x[i][j];
				}
			}
		}
		cout << endl;
	}
	static int kid = 0;
	imshow("ans" + to_string(kid++), img);
}

其中D:/base.jpg就是没有块的图:

运行效果:

2,直接求解

参考拼接覆盖问题,直接把12*31*7的所有组合全部求出来。

日历拼图全攻略:从规则解析到每日解法(附2022年2-6月完整答案) 本文提供日历拼图的全方位攻略,从核心规则解析到六大高效解题策略,帮助玩家系统掌握空间想象与逻辑推理技巧。文章深度剖析棋盘特性与拼板分类,并结合2022年2月至6月的实战案例,讲解如何优先处理复杂区域与拼板、利用平直性原则及回溯思维,最终建立个人解法体系,轻松应对每日挑战。 阅读详情

相关推荐

C# 解日历拼图(带星期)

IDE: Visual Studio 2012 Program.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DayPuzzle { class Program { /// <summary> /// 要解的月份 /// </summary> stati

咸咸咸鱼的博客 1518

日历拼图算法

日历拼图算法前言一、日历拼图是什么?1. 不带星期2. 带星期二、主要思想三、主要代码1. 定义拼图块2. 定义底板3. 拼图块初始化4. 遍历拼图块找一个解总结 前言 前几天刷抖音,发现有人在玩日历拼图,看起来还挺好玩的。一个拼图号称能拼出全年365天,于是上某宝一看,还有难度更高一级的,带星期的玩法,于是入手了一个玩。别说,还挺有意思的,就是有点浪费时间,有时候得花半个小时的时间去拼当天的拼图。 边玩边想,这个东西其实没什么技术含量,就是暴力法一直尝试,完全可以交给代码来完成。于是上 github 一

u012140251的博客 1万+

日历拼图算法解析:从规则到启发式搜索策略

本文深入解析了日历拼图这一经典益智游戏的算法本质与高效求解策略。文章揭示了其核心是一个精确覆盖问题,并系统阐述了六大启发式搜索策略,如复杂区域优先、复杂拼板先行等,以应对组合爆炸。同时,探讨了如何通过图像识别与回溯剪枝算法实现拼图解法的数字化与自动化求解,为玩家和开发者提供了从手动技巧到编程实现的完整指南。

weixin_29248653的博客 369

益智游戏日历拼图解法:搜索+回溯

先把盘子还有各个小块的形状记录起来,盘子用一个全局数组,而小块则用一个结构体node,还要存储长宽,并且有旋转等函数,然后采用深度优先搜索算法(DFS,这是一个很基础的算法,还没了解的应该先了解),注意回溯,然后就能罗列所有的情况,再加上一些剪枝、排序等等,5分钟内可以跑出结果!

PONY_10001的博客 2908

go:实现日历拼图算法(附完整源码)

go:实现日历拼图算法(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 237

A Puzzle A Day ANT PUZZLE 日历拼图 Python解

这是一个用Python编写的日历拼图求解程序,主要用来解决以下问题:给定8块不规则形状的拼图,在一个7x7的网格中拼出所有可能的日期组合。程序需要确保每次拼图都恰好留出两个空格,分别代表月份(1-12)和日期(1-31,根据月份不同天数不同)。 程序的核心算法采用深度优先搜索(DFS),通过不断尝试不同的拼图放置位置、旋转角度和翻转方式来寻找所有可能的解。为了提高运行效率,程序使用了多进程并行计算,同时利用NumPy进行矩阵运算,大大提升了计算速度。 此外,程序还包含了一些实用的功能,比如解的查重、结果

ikko的博客 1349

所有博客导航

。。

nameofcsdn的博客 1万+

calendar:事件渲染日历应用,fb 日历拼图

fb-日历-拼图 给定开始和结束时间的列表,它使用来显示日历中的事件。 事件以它们不重叠的方式显示并使用最大可用宽度。 安装和测试 npm install grunt test 解决方案 挑战是为给定事件使用最大可用空间。 这个解决方案相当简单和直接: 使用间隔树查找每个输入事件的重叠事件。 通过从总宽度中减去渲染宽度来计算宽度并将该事件划分为渲染。 对于每个事件从左 0 扫描以找到适合该事件的Kong。 演示

日历拼图的线性规划解法

日历拼图的线性规划解法

u013661233的博客 1616

fs-puzzle-helper:FS拼图助手。 一天之谜

FS Puzzle Helper是FS Puzzles的单用户求解器。 它也是拼图图像的切割器。 看起来如何 拼图形式 在“ FS拼图”字段中,您将复制要放入普通纸中的内容。 因此标题,昵称,网址(由制表符分隔)。 要直接从IITC快速复制数据,请使用 。 Ingress Mission编辑器也是如此: 。 角色图 绿色点标记表示起点(您在该列中找到的第一个门户)。 如果缺少门户,则会显示红色的虚线。 紫色实线是当您有两个注入的门户时。 有趣的事实:这是一张真实的地图。 您可以放大和缩小,但这是副作用,不是真正的功能 :slightly_smiling_face: 。 整个页面如下图所示。 第1至11列已折叠。 您可以通过单击列号(标题)来折叠列。 绿色门户就是完成的门户。 它们被标记为自动完成(当您填写FS拼图字段时)。 要求 您将需要使用PHP的服务器。 您可以使用随Linux一起分发的Apache HTTPD,也可

js实现日历的简单算法

主要为大家详细介绍了js实现日历的简单算法,用js写了一套日历,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

日历拼图C++解法

日历拼图C++解法 0.介绍 任何一个日期都可以用8块拼图拼起来。 如12月3日: 1.思路 主要的思想就是深度优先搜索。 a) 用字符串数组存8种拼图块 char a[9][5][5]={ {{'.','.','.','.'}, {'.','.','.','.'}, {'.','.','.','.'}, {'.','.','.','.'}}, {{'1','1','1','1'}, {'1','.','.','.'}, {'.','.','.','.'}, {'.','.','

Harris-H的博客 2482

IVP 2021 UNETR: Transformers for 3D Medical Image Segmentation

动机 具有跟踪和扩展路径的全卷积神经网络(FCNNs)(如编码器和解码器),近年来在各种医学图像分割应用中显示出了突出的地位。在这些体系结构中,编码器通过学习全局上下文表示来扮演一个不可或缺的角色,该全局上下文表示将进一步用于解码器的语义输出预测。 卷积层作为FCNN的主要构造块,其局部性限制了此类网络学习长时空间依赖的能力。 在NLP领域,基于transformer的模型已经在各种任务中实现了最先进的基准。transformer中的自我注意机制使他们能够动态地突出词序列的重要特征并学习其长时依赖关系。这

smile909的博客 1979

用Python的OR-Tools搞定日历拼图:保姆级建模与求解教程(附完整代码)

本文详细介绍了如何使用Python的OR-Tools工具包解决日历拼图问题,通过线性规划建模和CP-SAT求解器实现高效求解。教程包含从环境准备、数学模型构建到结果可视化的完整流程,并提供了优化技巧和完整代码示例,帮助开发者快速掌握组合优化问题的解法。

weixin_42546392的博客 222

RK3588部署Zipformer模型问题总结

本文分享了在RK3588嵌入式设备上部署小米Zipformer语音识别模型时遇到的问题及解决方法。主要遇到两个问题:1)在rknn_model_zoo例程编译时出现静态库版本不兼容,通过重新编译kaldi-native-fbank库并修改链接路径解决;2)sherpa-onnx编译时提示缺少portaudio库,通过修改编译脚本启用相关宏定义后成功编译。最终成功在RK3588上运行Zipformer模型,测试结果显示该模型具有较好的识别效果和实时性(RTF=0.22),验证了其在边缘设备上的适用性。

pkyang2004的博客 2148

从零实现地震波场模拟:交错网格有限差分法核心代码精讲

本文详细介绍了从零实现地震波场模拟的核心技术,重点讲解了交错网格有限差分法的实现过程。通过速度-应力弹性波方程的离散化处理,结合代码实例演示了应力与速度更新的关键步骤,并分享了震源加载、稳定性条件等实用技巧,为计算地球物理学研究提供实践指导。

weixin_42556197的博客 410

【原创-更新完毕】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载4

连载4。日历拼图的C语言详解。

3499

大陆毫米波雷达ARS408-21xx实战:从零搭建ROS环境下的目标检测与可视化

本文详细介绍了大陆毫米波雷达ARS408-21xx在ROS环境下的实战部署全流程。从硬件连接、CAN总线配置,到ROS驱动节点开发、CAN报文解析,再到RViz三维可视化实现,提供了完整的代码示例与调试技巧,帮助开发者快速搭建毫米波雷达目标检测与可视化系统。

open4的博客 634

【原创-更新完毕】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载1

日历拼图是一个有趣的游戏,每天都要拼一次。采用C语言的数组、指针、链表回调等知识编写解决方案,此游戏已被笔者成功解决。文章对这个游戏进行详细分析和展示代码。对有志于更进一步了解C语言的读者有较好帮助。

3513

【即插即用模块】Mamba篇 | CVPR 2025 | MaIR:新型Mamba扫描方式+通道混洗注意力,全任务涨点!

MaIR是一种新型图像恢复模型,通过嵌套S形扫描策略(NSS)和序列混洗注意力(SSA)改进传统Mamba方法。NSS采用条纹区域划分和S形扫描路径,既保留图像局部性又维持空间连续性;SSA通过通道洗牌和门控机制增强特征聚合。该模块创新性地融合多路径选择性扫描、深度卷积和注意力机制,在保持O(N)计算复杂度的同时,显著提升超分辨率和去噪等任务的性能表现(PSNR提升0.2-0.5dB)。代码实现包含特征洗牌、组卷积等关键操作,适用于高分辨率视觉任务,可作为即插即用组件替代传统自注意力模块。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 1168

2025 提高电力交易价格预测的疾风大模型方法综述

电力现货市场价格预测正转向大模型驱动的新范式。传统方法在极端波动、政策突变等场景下表现不佳,而Transformer、预训练时序模型(如Chronos-Bolt)和LLM混合框架展现出显著优势。关键技术包括多模态数据融合、两段式预训练微调、MoE架构和LLM-RAG增强解释性。案例显示,澳大利亚NSW市场误差降低43%,但混合模型路由仍必要。未来趋势涵盖数字孪生电网和多智能体竞价,需平衡模型创新与行业合规要求。大模型通过跨域学习与业务耦合提升预测,但需持续优化数据隐私、算力消耗和极端事件应对能力。

专注AI大模型,软件混淆,授权 1055

【原创-更新完毕】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载2

日历拼图是一个有趣的游戏,每天都要拼一次。采用C语言的数组、指针、链表回调等知识编写解决方案,此游戏已被笔者成功解决。文章对这个游戏进行详细分析和展示代码。对有志于更进一步了解C语言的读者有较好帮助。

1535

无人机威胁检测(Hostile Drone Detection)——基于YOLOv10与UI界面的实现

Anti-UAV数据集由多种场景下的无人机视频与图片组成,包含无人机目标的多样化姿态、背景、光照变化,专门用于反无人机检测研究。YOLO(You Only Look Once)系列是当前流行的实时目标检测算法,具有速度快、精度高的特点。网络结构优化:更深更轻的主干网络,提升特征提取能力。检测头改进:多尺度特征融合,更好检测小型目标如无人机。训练技巧:使用自动混合精度训练(AMP)、数据增强、标签平滑等技术。

YOLO 231

【原创-源码全文】|源码全文-日历拼图游戏的解决方案(C语言-进阶应用)-详解连载5

日历拼图是一个有趣的游戏,每天都要拼一次。采用C语言的数组、指针、链表回调等知识编写解决方案,此游戏已被笔者成功解决。文章对这个游戏进行详细分析和展示代码。对有志于更进一步了解C语言的读者有较好帮助。

2723

Android应用发布到Google Play的步骤和注意事项

发布Android应用到Google Play是将您的应用分享给全球用户的重要步骤。Google Play是Android平台上最大的应用分发渠道之一,使得开发者可以轻松将他们的应用推广到数百万的用户。在本篇博客中,我们将逐步介绍如何将您的Android应用发布到Google Play,同时提供详细的步骤和注意事项,以及相关的代码示例。

2201_76125261的博客 850

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【原创-更新完毕】|日历拼图游戏的解决方案(C语言-进阶应用)-详解连载3

连载3。日历拼图是一个有趣的游戏,每天都要拼一次。采用C语言的数组、指针、链表回调等知识编写解决方案,此游戏已被笔者成功解决。文章对这个游戏进行详细分析和展示代码。对有志于更进一步了解C语言的读者有较好帮助。

2854

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

上一篇: 一共九关
下一篇: 最强大脑解密
csuzhucong
博客等级 码龄11年 2665粉丝 943原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值