题目描述

在N*N的棋盘上(1<N≤10)填入1,2,...N*N共N*N个数,使得任意两个相邻的数之和为素数.例如,当N=2时,有 :

1

2

4

3

其相邻数的和为素数的有:1+2,1+4,4+3,2+3。

当N=4时,一种可以填写的方案如下:

1

2

11

12

16

15

8

5

13

4

9

14

6

7

10

3

在这里我们约定:左上角的格子里必须放数字1。

输入

一个正整数N。

输出

若有多种解,则需输出第一行之和最小,若第一行和相同,则输出第一列之和最小的排列方案;若无解,则输出"No solution"。若有解,第一行为空格分割的两个正整数,分别是该排列方案的第一行、第一列各数字之和。以下n行输出该排列方案,每个数字占4个字符,不足4位的在数字前用空格补齐。

样例输入

2

样例输出

3 5

1 2

4 3

算法分析

这题和洛谷上的不!一!样!!

输出格式:

如有多种解,则输出第一行、第一列之和为最小的排列方案;若无解,则输出“NO”。

洛谷上这题要求是:“如有多种解,则输出第一行、第一列之和为最小的排列方案”,只要搜到第一个解直接输出结束。但是这题不行,这题只能把所有解都搜过去。。。

要是爆搜肯定超时。。但是n小呀,于是开始了疯狂的预处理+剪枝。。。

因为要求输出第一行之和最小的排列方案,若第一行和相同,则输出第一列之和最小的排列方案。所以可以尝试先搜索第1行,接着再搜索第1列,最后再搜索中间那块。

初始化:

读入n,筛出2…2*n*n之间的所有素数表prime[i],用于表示i是否为素数。(线性筛,FindPrime())

对于每一个数i,找出2...2*n*n之内的所有能使i+j为素数的j,并储存起来。(predeal())

搜索第1行(workhang(int dx)):在搜索时可能判断当前已经搜索过的格子中数字之和hang是否大于先前答案中第一行的和ansh,如果是可不用继续搜索,这就是搜索剪枝。

搜索第1列(worklie(int dy)),同样,搜索列也可剪枝。

搜索中间部分(workmid(int dx,int dy)):只要已经出现过一个解,就不继续搜索,也可剪枝。而且竖着搜比横着搜快。(没有为什么。。数据就是这样。。。)

下面贴代码:

1 #include

2 #include

3 #include

4 #include

5 #define reg register

6 using namespacestd;7 int n,N;//N=n*n,即最大的数,方便以后遍历所有数(也省时间)

8 int map[11][11];//储存方阵

9 bool prime[20000], v[200];//prime[i]表示i是否为素数,v[i]表示i是否用过(用于搜索)

10

11 int pprime[20000];//用于筛素数

12 inline void FindPrime() { //筛素数,这里用的是线性筛,不懂可以去百度

13 int k=0, ls=2*N+5;14 memset(prime, 1, sizeof(prime));15 prime[1]=false;16 for (reg int i=1; i<=ls; ++i) {17 if (prime[i]) pprime[++k]=i;18 for (reg int j=1; j<=k; ++j) {19 prime[i*pprime[j]]=false;20 if (i%pprime[j]==0) break;21 }22 }23 }24 int pre[101][101];//存放预处理结果

25 inline void predeal(){//预处理

26 int k=2; //k:储存方案数

27 for(reg int i=1;i<=N;++i){28 k=2;29 for(reg int j=((i&1)?2:3);j<=N;j+=2){30 if(prime[j+i])31 pre[i][k++]=j;//将使i+j为素数的所有可能的j存入pre[i][2...k];

32 }33 pre[i][1]=k-2;//pre[i][1]存放方案数(j有几种可能),用于之后的遍历

34 }35 }36 int hang=1,lie=1;//hang:当前第一行所有数之和 lie:当前第一列所有数之和

37 int ansh = 1000, ansl = 1000,count=0;38 //ansh ansl:储存最优解(最小的hang lie);count:方案数(判断是否No solution)

39 int ansmap[11][11];//储存答案方阵

40 inline void print() {//简单的输出结果的函数

41 printf("%d %d\n", ansh, ansl);42 for (reg int i=1; i<=n; i++) {43 for (reg int j=1; j<=n; j++)44 printf("%4d", ansmap[i][j]);45 printf("\n");46 }47 }48 inline void update() {//更新结果(判断当前结果是否比上一个结果更优)

49 ansh = hang; ansl =lie;50 memcpy(ansmap, map, sizeof(map));51 count++;52 }53 bool found;//因为当第一行与第一列已经确定了时,中间这块对答案无影响,只要搜索出一个结果即可,用于剪枝

54 inline void workmid(int dx, intdy) {55 if(found)return;//只要中间这块已经被搜索出来了,即可停止

56 if((map[dx-1][dy]&1)^(map[dx][dy-1]&1))57 //若上面的数与左边的数一奇一偶,肯定不符合(i+left和i+up中必定有一个为偶数,非素数)

58 return;59 int left=map[dx-1][dy];//储存上面一格的数

60 for (reg int k = 2; k <= pre[left][1]+1; ++k) {61 int i=pre[left][k];//遍历使left+i为素数的所有i,后面写法与此相同

62 if (prime[i+map[dx][dy-1]] && !v[i]) {63 map[dx][dy]=i, v[i]=1;64 if (dx

65 else if (dx==n && dy

66 else if (dx==n && dy==n) update(), v[i]=0, found=1;//中间都搜完了,更新结果,标记found

67 }68 }69 }70 inline void worklie(int dy) {//搜索列

71 int up=map[dy-1][1];72 for (reg int k=2; k<=pre[up][1]+1; ++k) {73 int i=pre[up][k];74 if (!v[i] && (hang

82 int left=map[1][dx-1];83 for (reg int k=2; k<=pre[left][1]+1; ++k) {84 int i=pre[left][k];85 if (!v[i] && (hang+i)<=ansh){86 map[1][dx]=i, v[i]=1, hang+=i;87 if (dx==n) worklie(2), v[i]=0, hang-=i;88 else workhang(dx+1), v[i]=0, hang-=i;89 }90 }91 }92 intmain() {93 cin>>n; N=n*n;94 FindPrime();95 predeal();96 map[1][1] = 1;97 workhang(2);98 if(count>0)print(); else printf("No solution");99 return 0;100 }

数字拆分问题算法回溯_数字方阵2 题解 回溯算法相关推荐

  1. 数字图像处理与python实现_数字图像处理学习(2)—— 图像直方图均衡与图像匹配(python实现)...

    数字图像处理学习(2)-- 直方图均衡与图像匹配 1. 直方图均衡(Histogram Equalization) 1.1 直方图均衡化概念 1.2 直方图均衡实现简单思路 1.3 直方图均衡实现代码 ...

  2. 数字孪生体技术白皮书_数字孪生体的标准化之路

    致力于数字孪生体技术的研究与发展 通过解决方案和工程化应用造福人类 来源:数字孪生体实验室原创 作者:段海波 博士 转载请注明来源和出处 导  读 "无名万物之始,有名万物之母": ...

  3. 聚类算法 距离矩阵_论文阅读9——AP聚类算法

    Affinity Learning for Mixed Data Clustering 论文提出了基于混合对数据进行聚类的学习框架,具体研究内容包括:1)如何处理具有混合类型属性的数据.2)如何学习数 ...

  4. 机器学习算法 拟合曲线_制定学习曲线以检测机器学习算法中的错误

    机器学习算法 拟合曲线 机器学习 (Machine Learning) The learning curve is very useful to determine how to improve th ...

  5. otsu阈值分割算法原理_大津二值化算法OTSU的理解

    otsu 大津算法介绍: OTSU算法是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法. 利用阈值将原图像分成前景,背景两个图象. 前景:用n1,csum,m1来表示在当前阈值下的 ...

  6. 3算法全称_全网最通俗的KMP算法图解

    导语 本篇内容研究字符串匹配问题,首先介绍字符串匹配问题,引出Brute-Force算法及其优化方法,最后深入详解KMP算法.文章结构如下(全文阅读需要30分钟左右): 字符串匹配问题 1字符串匹配问 ...

  7. fp算法例题_机器学习(九)—FP-growth算法

    本来老师是想让我学Hadoop的,也装了Ubuntu,配置了Hadoop,一时间却不知从何学起,加之自己还是想先看点自己喜欢的算法,学习Hadoop也就暂且搁置了,不过还是想问一下园子里的朋友有什么学 ...

  8. python路径规划算法可视化_路径规划问题:DIJKSTRA算法 以及Python实现

    一. DJKSTRA算法概述 我们可以将地图抽象为Graph的数据结构,然后利用Graph的广度优先遍历算法(Breadth-First Search, BFS)解决无权重的High-Level的地图 ...

  9. 三维图形几何变换算法实验_基于深度学习的三维重建算法综述

    点击上方"计算机视觉life",选择"星标" 快速获得最新干货 00 前言 目前,三维重建技术已在游戏.电影.测绘.定位.导航.自动驾驶.VR/AR.工业制造以 ...

  10. rrt算法流程图_基于RRT的运动规划算法综述

    基于 RRT 的运动规划算法综述 1. 介绍 在过去的十多年中, 机器人的运动规划问题已经收到了大量的关注, 因为机器人开始成 为现代工业和日常生活的重要组成部分. 最早的运动规划的问题只是考虑如何移 ...

最新文章

  1. 运维基础(15) Linux 应急响应
  2. 界面无小事(八):RecyclerView增删item
  3. 5G 落地进入爆发期,是时候让毫米波登场了
  4. struts2显示列表序号的办法
  5. 《人民邮电出版社9本计算机教材的教学课件(计算机老师的宝贝)》
  6. Controller、Service、Dao进行Junit单元
  7. Halcon 学习总结——制作标定板(函数gen_caltab)
  8. access mysql 操作方法_设置和取消Access数据库密码-图解教程
  9. Crypto-js加密解密
  10. 智能推送LeetCode中文站点题目思路解析
  11. 高性能抗干扰宽带自组网电台——T3M2-20W视距100km测试
  12. cad老是弹出命令中发生异常_CAD为什么会异常退出?遇到CAD异常退出怎么办-百度经验...
  13. torch.ones理解
  14. java 俄罗斯方块 教程_俄罗斯方块
  15. 父爱动画代码python_情人节锦囊:简单的python表白程序(动画效果)
  16. css3+html5——机器猫哆啦A梦+手、脚、头动起来!
  17. erp仓储管理 java,关于java:ERP仓库管理的操作与设计开源软件诞生20
  18. 图片点击放大,你的网页也能做到!
  19. Ubuntu 安装 libvirt
  20. 忽略' scanf '的返回值,用属性warn_unused_result声明的疑问

热门文章

  1. 【达梦数据库+下载+安装+可视工具】
  2. 从早吃到晚,才是我对旅行目的地最大的尊重
  3. 少儿创意学编程(Scratch基础篇):第1课——摇滚乐队
  4. 4g内存只识别2.5g的解决办法
  5. WPS或word编辑公式后行间距变大与公式浮动问题
  6. 跟谁学市值赶超新东方,在线教育究竟哪家强?
  7. JAVA计算机毕业设计珠宝首饰进销存管理系统Mybatis+系统+数据库+调试部署
  8. 关于知乎和csdn “提问“感触
  9. Map集合遍历键找值的方式
  10. Facebook COO桑德伯格