数字拆分问题算法回溯_数字方阵2 题解 回溯算法
题目描述
在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 题解 回溯算法相关推荐
- 数字图像处理与python实现_数字图像处理学习(2)—— 图像直方图均衡与图像匹配(python实现)...
数字图像处理学习(2)-- 直方图均衡与图像匹配 1. 直方图均衡(Histogram Equalization) 1.1 直方图均衡化概念 1.2 直方图均衡实现简单思路 1.3 直方图均衡实现代码 ...
- 数字孪生体技术白皮书_数字孪生体的标准化之路
致力于数字孪生体技术的研究与发展 通过解决方案和工程化应用造福人类 来源:数字孪生体实验室原创 作者:段海波 博士 转载请注明来源和出处 导 读 "无名万物之始,有名万物之母": ...
- 聚类算法 距离矩阵_论文阅读9——AP聚类算法
Affinity Learning for Mixed Data Clustering 论文提出了基于混合对数据进行聚类的学习框架,具体研究内容包括:1)如何处理具有混合类型属性的数据.2)如何学习数 ...
- 机器学习算法 拟合曲线_制定学习曲线以检测机器学习算法中的错误
机器学习算法 拟合曲线 机器学习 (Machine Learning) The learning curve is very useful to determine how to improve th ...
- otsu阈值分割算法原理_大津二值化算法OTSU的理解
otsu 大津算法介绍: OTSU算法是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法. 利用阈值将原图像分成前景,背景两个图象. 前景:用n1,csum,m1来表示在当前阈值下的 ...
- 3算法全称_全网最通俗的KMP算法图解
导语 本篇内容研究字符串匹配问题,首先介绍字符串匹配问题,引出Brute-Force算法及其优化方法,最后深入详解KMP算法.文章结构如下(全文阅读需要30分钟左右): 字符串匹配问题 1字符串匹配问 ...
- fp算法例题_机器学习(九)—FP-growth算法
本来老师是想让我学Hadoop的,也装了Ubuntu,配置了Hadoop,一时间却不知从何学起,加之自己还是想先看点自己喜欢的算法,学习Hadoop也就暂且搁置了,不过还是想问一下园子里的朋友有什么学 ...
- python路径规划算法可视化_路径规划问题:DIJKSTRA算法 以及Python实现
一. DJKSTRA算法概述 我们可以将地图抽象为Graph的数据结构,然后利用Graph的广度优先遍历算法(Breadth-First Search, BFS)解决无权重的High-Level的地图 ...
- 三维图形几何变换算法实验_基于深度学习的三维重建算法综述
点击上方"计算机视觉life",选择"星标" 快速获得最新干货 00 前言 目前,三维重建技术已在游戏.电影.测绘.定位.导航.自动驾驶.VR/AR.工业制造以 ...
- rrt算法流程图_基于RRT的运动规划算法综述
基于 RRT 的运动规划算法综述 1. 介绍 在过去的十多年中, 机器人的运动规划问题已经收到了大量的关注, 因为机器人开始成 为现代工业和日常生活的重要组成部分. 最早的运动规划的问题只是考虑如何移 ...
最新文章
- 运维基础(15) Linux 应急响应
- 界面无小事(八):RecyclerView增删item
- 5G 落地进入爆发期,是时候让毫米波登场了
- struts2显示列表序号的办法
- 《人民邮电出版社9本计算机教材的教学课件(计算机老师的宝贝)》
- Controller、Service、Dao进行Junit单元
- Halcon 学习总结——制作标定板(函数gen_caltab)
- access mysql 操作方法_设置和取消Access数据库密码-图解教程
- Crypto-js加密解密
- 智能推送LeetCode中文站点题目思路解析
- 高性能抗干扰宽带自组网电台——T3M2-20W视距100km测试
- cad老是弹出命令中发生异常_CAD为什么会异常退出?遇到CAD异常退出怎么办-百度经验...
- torch.ones理解
- java 俄罗斯方块 教程_俄罗斯方块
- 父爱动画代码python_情人节锦囊:简单的python表白程序(动画效果)
- css3+html5——机器猫哆啦A梦+手、脚、头动起来!
- erp仓储管理 java,关于java:ERP仓库管理的操作与设计开源软件诞生20
- 图片点击放大,你的网页也能做到!
- Ubuntu 安装 libvirt
- 忽略' scanf '的返回值,用属性warn_unused_result声明的疑问
热门文章
- 【达梦数据库+下载+安装+可视工具】
- 从早吃到晚,才是我对旅行目的地最大的尊重
- 少儿创意学编程(Scratch基础篇):第1课——摇滚乐队
- 4g内存只识别2.5g的解决办法
- WPS或word编辑公式后行间距变大与公式浮动问题
- 跟谁学市值赶超新东方,在线教育究竟哪家强?
- JAVA计算机毕业设计珠宝首饰进销存管理系统Mybatis+系统+数据库+调试部署
- 关于知乎和csdn “提问“感触
- Map集合遍历键找值的方式
- Facebook COO桑德伯格