NOIP2022提高组复赛题解
- 格式:docx
- 大小:40.07 KB
- 文档页数:6
NOIP提⾼组CSP-S复赛需掌握的算法1、排序算法(快排、选择、冒泡、堆排序、⼆叉排序树、桶排序)2、DFS/BFS 也就是搜索算法,剪枝务必要学!学宽搜的时候学⼀下哈希表!3、树①遍历②⼆叉树③⼆叉排序树(查找、⽣成、删除)④堆(⼆叉堆、左偏树、堆排序)⑤Trie树4、图(图论建模)①最⼩⽣成树②最短路径③计算图的传递闭包④连通分量(其中要掌握并查集技术)强连通分量tarjin⑤拓扑排序、关键路径⑥哈密尔顿环⑦欧拉回路(USACO 3.3 题1 Fence)⑧Bell-man Ford、SPFA(能解决负权回路)(USACO 3.2 题6 Butter)⑨⼆分图(匈⽛利算法)(USACO 4.2 题2 stall)5、动态规划(背包问题只是其中⼀种)①线性动规②区间动规③树形动规④图形动规6、分治(掌握了动规分治就好学了)7、贪⼼8、位运算(可以⽤来进⾏优化)——————————————————————————————————————————————————————————————————————————————————————补充:时间复杂度(渐近时间复杂度的严格定义,NP问题,时间复杂度的分析⽅法,主定理)排序算法(平⽅排序算法的应⽤,Shell排序,快速排序,归并排序,时间复杂度下界,三种线性时间排序,外部排序)数论(整除,集合论,关系,素数,进位制,辗转相除,扩展的辗转相除,同余运算,解线性同余⽅程,中国剩余定理)指针(链表,搜索判重,邻接表,开散列,⼆叉树的表⽰,多叉树的表⽰)按位运算(and,or,xor,shl,shr,⼀些应⽤)图论(图论模型的建⽴,平⾯图,欧拉公式与五⾊定理,求强连通分量,求割点和桥,欧拉回路,AOV问题,AOE问题,最⼩⽣成树的三种算法,最短路的三种算法,标号法,差分约束系统,验证⼆分图,Konig定理,匈⽛利算法,KM算法,稳定婚姻系统,最⼤流算法,最⼩割最⼤流定理,最⼩费⽤最⼤流算法)计算⼏何(平⾯解⼏及其应⽤,向量,点积及其应⽤,叉积及其应⽤,半平⾯相交,求点集的凸包,最近点对问题,凸多边形的交,离散化与扫描)数据结构(⼴度优先搜索,验证括号匹配,表达式计算,递归的编译,Hash表,分段Hash,并查集,Tarjan算法,⼆叉堆,左偏树,斜堆,⼆项堆,⼆叉查找树,AVL,Treap,Splay,静态⼆叉查找树,2-d树,线段树,⼆维线段树,矩形树,Trie树,块状链表)组合数学(排列与组合,鸽笼原理,容斥原理,递推,Fibonacci数列,Catalan数列,Stirling数,差分序列,⽣成函数,置换,Polya原理)概率论(简单概率,条件概率,Bayes定理,期望值)矩阵(矩阵的概念和运算,⼆分求解线性递推⽅程,多⽶诺⾻牌棋盘覆盖⽅案数,⾼斯消元)字符串处理(KMP,后缀树,有限状态⾃动机,Huffman编码,简单密码学)动态规划(单调队列,凸完全单调性,树型动规,多叉转⼆叉,状态压缩类动规,四边形不等式)博弈论(Nim取⼦游戏,博弈树,Shannon开关游戏)搜索(A,ID,IDA,随机调整,遗传算法)微积分初步(极限思想,导数,积分,定积分,⽴体解析⼏何……。
第一题题库NOIP20071.统计数字(count.pas/c/cpp)【问题描述】某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*109)。
已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。
【输入】输入文件count.in包含n+1行:第1行是整数n,表示自然数的个数。
第2~n+1行每行一个自然数。
【输出】输出文件count.out包含m行(m为n个自然数中不相同数的个数),按照自然数从小到大的顺序输出。
每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。
【输入输出样例】【限制】40%的数据满足:1<=n <=100080%的数据满足:1<=n <=50000100%的数据满足:1<=n <=200000,每个数均不超过1 500 000 000(1.5*109)NOIP20081. 笨小猴(wird.pas/c/cpp)【问题描述】笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼。
但是他找到了一种方法,经试验证明,用这种方法去选择选项的时候选对的几率非常大!这种方法的具体描述如下:假设maxn 是单词中出现次数最多的字母的出现次数,minn 是单词中出现次数最少的字母的出现次数,如果maxn-minn 是一个质数,那么笨小猴就认为这是个Lucky Word ,这样的单词很可能就是正确的答案。
【输入】输入文件word.in 只有一行,是一个单词,其中只可能出现小写字母,并且长度小于100。
【输出】输出文件word.out 共两行,第一行是一个字符串,假设输入的的单词是Lucky Word ,那么输出“Lucky Word ”,否则输出“No Answer ”;第二行是一个整数,如果输入单词是Lucky Word,输出maxn-minn 的值,否则输出0。
noip普及组复赛试题及答案一、选择题1. 在计算机科学中,以下哪个概念与数据结构最相关?A. 算法B. 操作系统C. 网络协议D. 编译原理答案:A2. 以下哪种排序算法的时间复杂度为O(n^2)?A. 快速排序B. 归并排序C. 堆排序D. 冒泡排序答案:D3. 在C++中,以下哪个关键字用于定义类?A. structB. unionC. enumD. typedef答案:A4. 以下哪个选项不是数据库管理系统(DBMS)的特性?A. 数据持久性B. 数据共享C. 数据加密D. 数据独立性答案:C5. 在计算机网络中,TCP和UDP协议分别属于哪一层?A. 传输层B. 应用层C. 网络层D. 物理层答案:A二、填空题1. 在计算机程序中,______ 用于定义数据的存储方式和组织形式。
答案:数据结构2. 一个算法的时间复杂度为O(1),表示该算法的执行时间与输入数据的规模______。
答案:无关3. 在C++中,______ 是一种特殊的类,它提供了一种方式来定义数据类型。
答案:typedef4. 数据库管理系统(DBMS)通常包含数据定义语言(DDL)、数据操纵语言(DML)和______。
答案:数据控制语言(DCL)5. 在计算机网络中,______ 协议负责在网络层进行数据包的路由选择。
答案:IP三、简答题1. 请简述面向对象编程(OOP)的三个基本特征。
答案:封装、继承、多态2. 描述二分查找算法的基本步骤。
答案:二分查找算法的基本步骤包括:首先确定数组是有序的,然后取中间元素与目标值比较,如果中间元素等于目标值,则查找成功;如果目标值小于中间元素,则在左半部分继续查找;如果目标值大于中间元素,则在右半部分继续查找,直到找到目标值或查找范围为空。
四、编程题1. 编写一个函数,实现对整数数组的排序。
答案:以下是一个简单的冒泡排序算法实现:```cppvoid bubbleSort(int arr[], int n) {for (int i = 0; i < n-1; i++) {for (int j = 0; j < n-i-1; j++) {if (arr[j] > arr[j+1]) {swap(arr[j], arr[j+1]);}}}}```2. 编写一个函数,实现计算一个整数的阶乘。
Day1铺地毯【问题描述】为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。
一共有n 张地毯,编号从1 到n。
现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。
地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。
注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。
【输入】输入文件名为 carpet.in。
输入共 n+2 行。
第一行,一个整数 n,表示总共有n 张地毯。
接下来的 n 行中,第i+1 行表示编号i 的地毯的信息,包含四个正整数a,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a,b)以及地毯在x轴和y 轴方向的长度。
第 n+2 行包含两个正整数x 和y,表示所求的地面的点的坐标(x,y)。
【输出】输出文件名为 carpet.out。
输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出-1。
【输入输出样例 1】【输入输出样例说明】如下图,1 号地毯用实线表示,2 号地毯用虚线表示,3 号用双实线表示,覆盖点(2,2)的最上面一张地毯是3 号地毯。
【输入输出样例 2】【输入输出样例说明】如上图,1 号地毯用实线表示,2 号地毯用虚线表示,3 号用双实线表示,点(4,5)没有被地毯覆盖,所以输出-1。
【数据范围】对于 30%的数据,有n≤2;对于 50%的数据,0≤a, b, g, k≤100;对于 100%的数据,有0≤n≤10,000,0≤a, b, g, k≤100,000。
【一句话题意】给定n个按顺序覆盖的矩形,求某个点最上方的矩形编号。
【考察知识点】枚举【思路】好吧我承认看到图片的一瞬间想到过二维树状数组和二维线段树。
置答案ans=-1,按顺序枚举所有矩形,如果点在矩形内则更新ans。
注意题中给出的不是对角坐标,实际上是(a,b)与(a+g,b+k)。
NOIP2023提高组解题报告1. 前言NOIP(全国信息学奥林匹克竞赛)是中国非常重要的信息学竞赛之一,旨在选拔和培养高中阶段的优秀信息学人才。
在NOIP中,提高组是一个相对较高难度的组别,要求选手具备扎实的编程基础和复杂问题的解决能力。
在本文档中,将对NOIP2023提高组的解题情况进行详细的报告和分析。
2. 题目概览本次NOIP2023提高组共计有以下几道题目:1.田忌赛马(Tianji Race)2.矩阵乘法(Matrix Multiplication)3.数字问题(Number Problem)4.字符串排序(String Sort)下面将对每道题目的解题思路和实现进行详细说明。
3. 田忌赛马田忌赛马是第一道题目,题目要求给出两组马匹的速度,分别是田忌的马匹和齐王的马匹,然后判断田忌最多能赢齐王多少场比赛。
解题思路非常简单,只需要对田忌和齐王的马匹进行排序,从最快的马开始进行配对比赛。
如果田忌的马比齐王的马快,那么田忌赢得这场比赛,分数加一;否则,田忌选择最慢的马匹进行比赛。
通过这样的遍历方式,最后的得分就是田忌能够赢得比赛的场数。
具体实现代码如下:def solve(Tianji, QiWang):Tianji.sort()QiWang.sort()t_index =0q_index =0score =0while t_index < len(Tianji) and q_index < len(QiWang):if Tianji[t_index] > QiWang[q_index]:score +=1t_index +=1q_index +=1else:t_index +=1return score4. 矩阵乘法矩阵乘法是第二道题目,题目需要实现一个矩阵乘法的算法。
解题思路比较直接,使用两层循环对两个矩阵进行迭代计算,然后累加乘积,得到最终结果。
具体实现代码如下:def multiply_matrix(A, B):row_A = len(A)col_A = len(A[0])col_B = len(B[0])C = [[0] * col_B for _ in range(row_A)]for i in range(row_A):for j in range(col_B):for k in range(col_A):C[i][j] += A[i][k] * B[k][j]return C5. 数字问题数字问题是第三道题目,题目要求给出一个正整数n,判断是否存在一个正整数x,使得n的位数的立方和等于x。
Noip提高组复赛知识点1. 简介NOIP(National Olympiad in Informatics in Provinces)是中国计算机学会主办的全国性计算机竞赛。
它分为初赛和复赛两个阶段,复赛则进一步分为提高组和普及组。
本文将重点介绍NOIP提高组复赛的知识点。
2. 复赛知识点2.1 数据结构在NOIP提高组复赛中,对数据结构的理解和应用是非常重要的。
以下是一些常见的数据结构及其应用:2.1.1 数组数组是一种线性数据结构,可以在O(1)的时间复杂度内访问任意位置的元素。
在复赛中,经常需要使用数组来解决一些简单的问题,如统计字符出现次数、记录中间结果等。
2.1.2 链表链表是一种动态数据结构,它通过指针将多个节点连接起来。
在复赛中,链表常常用于实现一些特定的数据结构,如队列、栈等。
2.1.3 栈和队列栈和队列是两种基本的数据结构。
栈是一种后进先出(LIFO)的数据结构,而队列是一种先进先出(FIFO)的数据结构。
它们在复赛中的应用非常广泛,如深度优先搜索(DFS)和广度优先搜索(BFS)等算法中常常使用栈和队列来辅助实现。
2.1.4 树和图树和图是两种重要的非线性数据结构。
树是一种层次结构,图是一种由节点和边组成的网络结构。
在复赛中,树和图常常用于解决一些复杂的问题,如最短路径、最小生成树等。
2.2 算法和技巧在NOIP提高组复赛中,算法和技巧的掌握是至关重要的。
以下是一些常见的算法和技巧:2.2.1 动态规划动态规划是一种将复杂问题分解成简单子问题的方法,通过保存子问题的解来避免重复计算。
在复赛中,动态规划常常用于解决一些涉及最优化问题的算法。
2.2.2 贪心算法贪心算法是一种每一步都选择当前最优解的算法。
在复赛中,贪心算法常常用于解决一些涉及最优解问题的算法,如最小生成树问题、最短路径问题等。
2.2.3 搜索算法搜索算法是一种通过遍历问题的所有可能解空间来寻找解的方法。
在复赛中,搜索算法常常用于解决一些复杂的问题,如深度优先搜索(DFS)、广度优先搜索(BFS)等。
NOIP复赛复习20数论算法巩固与提高一、数论1.数整数、自然数(大于等于0的整数)、正整数(大于0的整数)、负整数、非负整数、非正整数、非零整数、奇数偶数。
2.整除性设a,b∈Z,如果存在c∈Z并且a=bc,则称b|a(b为a的因子,“|”表示“能整除”)3.质数如果一个数,只有1和自身作为因子的数,叫做质数(素数)。
通论1:存在一个质数p,若p|ab,则p|a或者p|b。
通论2:若p|a或者(p,a)=1(p和a的最大公因子为1),则p|a2可以推出 p|a。
通论3:用π(x)表示不超过x的质数的个数,可以证:limπ(x)lnx÷x=1,换种通俗说法就是:1~x的质数个数大约为x/lnx(证明时间复杂度时可以用)。
4.质数的判定(1)一个很多人都在用的办法(判断一个较小的数是否为质数):bool prime(int x)//判断质数时间复杂度:O(sqrt(x)),最多1012~1014{if(x<2) return false;for(int a=2;a*a<=x;a++){if(x%a==0) return false;//不是质数}return true;//是质数}(2)运用费马小定理:p为一个素数且p不是a的倍数,则有:a p-1≡1(mod p)(不能从右边推到左边)做法:多次选取a检验p是否满足费马小定理(说明p可能是质数,选的满足条件的a越多,p为质数的可能性越大)。
时间复杂度为:O(klogp),选取k个a,判断的过程用掉logp,总的加起来为klogp。
特别地,这样的算法有缺陷,因为有Carmichael数的存在,可导致上述算法给出一个错误的判断,例如:561、1105、1729,这三个数满足费马小定理,但是它们都是合数!这里给出1~10000的Carmichael数:561、1105、1729、2465、2821、6601、8911。
(3)Miller-Rabin算法(判断一个很大的数是否为质数):由于Carmichael数的存在,并且Carmichael数是有无穷多个的,那怎么办?打表?肯定不行啊!所以就要加强这个算法!如果n为素数,取a<n,令n-1=d×2r,则要么a d≡1(mod n),要么存在一个数i满足:0≤i<r,使得:a d×2^i≡-1(mod n),“一个数mod n=-1”可以表示为:“一个数mod n=n-1”,同样地也是不能从右边推到左边。
NOI*n的矩阵中,只能向下、右两个方向走,找到两条互不相交的路径,使得两条路径上的权值之和最大。
【题目类型】双线程动态规划【建议编程时间】40分钟。
这里的编程时间包括调试时间。
【空间复杂度】约27M,全局变量完全可承受。
50*50*50*50*ieofint=*10^7【解题分析】1、读入矩阵,注意行列。
2、采用一个四维数组记录当前两条路走到的位置i1,1,i2,2时取得的最大值,初始化为0,表示不可能到达。
0,0,0,0为1,最后减1输出。
3、一个四重循环枚举两条路分别走到的位置。
由于每个点均从上或左继承而来,故内部有四个if,分别表示两个点从上上、上左、左上、左左继承来时,加上当前两个点所取得的最大值。
例如,f[i][][][] = ma{f[i][][][], f[i-1][][-1][] a[i][] a[][]},表示两点均从上面位置走来。
4、输出右下角处的最大值f[m][n][m][n],注意换行。
【编程注意】1、在数组边界处特殊处理,避免数组越界。
2、若待继承的点最大值为零,则停止判断,不能从这里走来。
3、显然,非矩阵右下角的汇合点,两个位置不能重合(否则路径相交),若重合则最大值为0,不可达。
4双栈排序【问题描述】通过两个栈S1,S2,将一个给定的输入序列升序排列。
定义a操作将元素压入S1栈,b操作从S1栈中取出栈顶元素,c操作将元素压入S2栈,d操作从S2栈中取出栈顶元素。
求字典序最小的操作序列。
【建议编程时间】贪心算法40分钟(包括调试),可得30分。
【解题分析】(贪心算法,30分)1、读入序列2、若能进入S1栈,则执行a操作,进入S1栈;重复执行b操作,将S1栈中当前元素弹出,直到不可行为止。
3、若能进入S2栈(c),并将S2中符合要求的元素弹出(d),直到不可行。
4、若两栈均无法进入,失败退出5、输出操作序列【判断是否能进栈】若当前元素小于栈顶元素,则进栈,栈元素个数自增;否则不能进栈。
2022noip复赛模拟练习15(答案)【试题描述】有一组数(设有N个)。
编一程序交换这组数中任意指定的两段。
【输入描述】一个数N(不超过20个)一行N个数由空格分开两个空格分开的数(表示要交换的其中一段)两个空格分开的数(表示要交换的其中另一段)【输出描述】交换后的一行数(中间用空格隔开)【输入样例】16361145237067342689901556502010351315【输出样例】365650207067342689901511452310programe某1146;vari,j,n,k,a1,b1,a2,b2:integer;a,b:array[0..20]oflongint;pro ceduremake(某,y:integer);vari:integer;beginfori:=某toydobegininc(k);b[k]:=a[i];end;end;beginreadln(n);fori:=1tondoread(a[i]);readln(a1,b1);readln(a2,b2);k:=0;make(1,a1-1);make(a2,b2);make(b1+1,a2-1);make(a1,b1);make(b2+1,n);fori:=1tondowrite(b[i],'');end.14215678910305411997723864736251013Shuchu2772386473054119915678910361742年6月7日哥德巴赫写信给当时的大数学家欧拉,正式提出了以下的猜想:任何一个大于9的奇数都可以表示成3个质数之和。
质数是指除了1和本身之外没有其他约数的数,如2和11都是质数,而6不是质数,因为6除了约数1和6之外还有约数2和3。
需要特别说明的是1不是质数。
这就是哥德巴赫猜想。
欧拉在回信中说,他相信这个猜想是正确的,但他不能证明。
从此,这道数学难题引起了几乎所有数学家的注意。
NOIP2022提高组复赛题解第一题笨小猴某题目描述:笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼。
但是他找到了一种方法,经试验证明,用这种方法去选择选项的时候选对的几率非常大!这种方法的具体描述如下:假设ma某n是单词中出现次数最多的字母的出现次数,minn是单词中出现次数最少的字母的出现次数,如果ma某n-minn是一个质数,那么笨小猴就认为这是个LuckyWord,这样的单词很可能就是正确的答案。
输入格式:输入文件word.in只有一行,是一个单词,其中只可能出现小写字母,并且长度小于100。
某输出格式:输出文件word.out共两行,第一行是一个字符串,假设输入的的单词是LuckyWord,那么输出“LuckyWord”,否则输出“NoAnwer”;第二行是一个整数,如果输入单词是LuckyWord,输出ma某n-minn的值,否则输出0。
样例1输入:error输出:LuckyWord2解释:单词error中出现最多的字母r出现了3次,出现次数最少的字母出现了1次,3-1=2,2是质数。
样例2输入:olymipic输出:NoAnwer0解释:单词olympic中出现最多的字母i出现了2次,出现次数最少的字母出现了1次,2-1=1,1不是质数。
思路:统计单词中每个字母的出现次数,挑出最多的次数和最少的次数(不包括0次),相减判断是否为质数即可。
判断质数时可以写函数判断,也可以把100以内的质数列成常量数组直接判断,因为单词最多只有100个字母。
需要注意的是输出时的LWNA四个字母要大写。
某总结:这是一道送分题,没有什么难度,需要注意的细节也不多,所以在比赛中是一定要拿满分的。
参考样程#include<ftream>#include<tring>#include<cmath>#defineI_F"word.in "#defineO_F"word.out"uingnamepacetd;tring;hortan;voidInput();voi dSearch();boolPd();voidOutput();intmain(){Input();Search();Output();return0;}voidInput(){iftreamfin(I_F);fin>>;fin.cloe();}voidS earch()//统计字母出现次数{horti,ma某=0,min=200;hortf[26]={0};for(i=0;i<.length();f[[i++]-'a']++);for(i=0;i<26;i++)if(f[i]>0){if(f[i]>ma某)ma某=f[i];if(f[i]<min)min=f[i];}an=ma某-min;}boolPd()//判断质数{if(an==1)returnfale;eleif(an==2)returntrue;eleif(an%2==0)return fale;elefor(horti=3;i<=qrt((double)an);i+=2)if(an%i==0)returnfal e;returntrue;}voidOutput(){oftreamfout(O_F);if(Pd())fout<<"LuckyWord\n"<<an<<endl;elefout<<"NoAnwer\n0\n";fout.cloe();}第二题火柴棒等式问题描述:给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。
用火柴棍拼数字0-9的拼法如图所示:(图略)注意:1.加号与等号各自需要两根火柴棍2.如果A≠B,则A+B=C与B+A=C视为不同的等式(A、B、C>=0)3.n根火柴棍必须全部用上输入格式:输入文件matche.in共一行,有一个整数n(n<=24)。
某输出格式:输出文件matche.out共一行,表示能拼成的不同等式的数目。
样例1输入:14输出:2解释:2个等式为0+1=1和1+0=1。
样例2输入:18输出:9解释:9个等式为:0+4=4、0+11=11、1+10=11、2+2=4、2+7=9、4+0=4、7+2=9、10+1=11、11+0=11思路:枚举两加数,计算所需火柴棒是否等于n。
枚举范围0~1000。
总结:这也是比较水的一道题,数据规模较小,算法简单,比赛中这样的题也应该拿到满分。
参考样程#include<ftream>#defineI_F"matche.in"#defineO_F"matche.out"#defi neMA某1000uingnamepacetd;conthortmatch[10]={6,2,5,5,4,5,6,3,7,6};//10个数字所需火柴棒longan;hortn;voidInput();intMatche(int某);voidSearch();voidOutput();intmain(){Input();Search();Output( );}voidInput(){iftreamfin(I_F);fin>>n;fin.cloe();}intMatche(int 某)//计算摆出某所需的火柴棒{intt=某,=0;if(某==0)return6;elewhile(t>0){+=match[t%10];t/=10;}return;}voidSearch(){inti,j;n-=4;for(i=0;i<MA某;i++)for(j=0;j<=i;j++)//这样对于A+B和B+A就只会搜索到一次,可以节约一半时间if(Matche(i)+Matche(j)+Matche(i+j)==n){if(i!=j)an+=2;elean++;}}//Output函数略第三题传纸条问题描述:小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。
一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。
幸运的是,他们可以通过传纸条来进行交流。
纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。
从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。
在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。
班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。
反之亦然。
还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。
小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度只和最大。
现在,请你帮助小渊和小轩找到这样的两条路径。
输入格式:输入文件meage.in的第一行有2个用空格隔开的整数m和n,表示班里有m行n列(1<=m,n<=50)。
接下来的m行是一个m某n的矩阵,矩阵中第i行jmm某nij列的整数表示坐在第i行j列的学生的好心程度。
每行的n个整数之间用空格隔开。
输出格式:输出文件meage.out共一行,包含一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。
样例输入:33039285570输出:34数据规模:30%的数据满足:1<=m,n<=10100%的数据满足:1<=m,n<=50思路:首先想到搜索,但是对于只考虑一条路线来说,每一步有两种状态一共要走m+n步,搜索整棵树的时间复杂度为O(2^(m+n)),如果两条路线都考虑的话,时间复杂度为O(4^(m+n)),即使是30%的数据,即m+n=20,4^20≈10^12,这样的数据规模也还是太大了。
4维动态规划本题可以使用动态规划法解决。
设f[i,j,k,l]为第一条线走到(I,j),第二条线走到(k,l)时的最优值(方便起见,两条线都看作从左上角开始,右下角结束)。
动态转移方程:f[i-1,j,k-1,l](i>1)f[i,j,k,l]=minf[i-1,j,k,l-1](i>1)+[i,j]+[k,l]f[i,j-1,k-1,l](j>1)且(k>i+1)f[I,j-1,k,j-1](j>1)同时,由于两条线不能交叉,有k>i。
状态压缩因为两条路线长度相等,所以有i+j=k+l,则状态可以压缩为三维,压缩后的转移方程为:f[i-1,j,k-1](i>1)f[i,j,k]=minf[i-1,j,k](i>1)+[i,j]+[k,i+j-k]f[i,j-1,k-1](j>1)且(k>i+1)f[I,j-1,k](j>1)关于k>i+1:当k=i+1时,(i,j-1)和(k-1,i+j-k)是同一点,由于两条路线不可交叉,所以两条路线的状态不可能由同一点发展而来。
总结:这是一道较高难度的动规题,有一个小陷阱(如果把两条线分开做动态规划则会由于两条线路可能交叉而出错),边界条件也较为复杂,并且需要状态压缩才能拿满分。
在比赛中遇到这种题如果一时无法找到合适的算法,最好先做下一题,因为即使写搜索也无法过多少数据。
同时在考虑动态转移方程时一定要注意边界条件,否则极易出错。
#include<ftream>#defineI_F"meage.in"#defineO_F"meage.out"uin gnamepacetd;hortn,m;hort[60][60];longf[60][60][60];voidInput();l ongma某(longa,longb);voidDyna();voidOutput();intmain(){Input();Dyna();O utput();return0;}voidInput(){horti,j;iftreamfin(I_F);fin>>n>>m;f or(i=0;i<n;i++)for(j=0;j<m;fin>>[i][j++]);fin.cloe();}voidOutput (){oftreamfout(O_F);fout<<f[n-2][m-1][n-1]<<endl;//不要输出f[n-1][m-1][n-1],正确的方程是不会计算这个状态的fout.cloe();}longma某(longa,longb){if(a>b)returna;elereturnb;}voidDyna(){horti,j,k;fo r(i=0;i<n;i++)for(j=0;j<m;j++)for(k=i+1;k<=i+j;k++)if (k==i+1)//需要格外注意边界条件if(i==0)f[i][j][k]=f[i][j-1][k]+[i][j]+[k][i+j-k];eleif(j==0)f[i][j][k]=ma某(f[i-1][j][k],f[i-1][j][k-1])+[i][j]+[k][i+j-k];elef[i][j][k]=ma某(ma某(f[i-1][j][k],f[i-1][j][k-1]),f[i][j1][k])+[i][j]+[k][i+j-k];eleif(i==0)f[i][j][k]=ma某(f[i][j-1][k-1],f[i][j-1][k])+[i][j]+[k][i+j-k];eleif(j==0)f[i][j][k]=ma某(f[i-1][j][k],f[i-1][j][k-1])+[i][j]+[k][i+j-k];elef[i][j][k]=ma某(ma某(f[i-1][j][k],f[i-1][j][k-1]),ma某(f[i][j1][k-1],f[i][j-1][k]))+[i][j]+[k][i+j-k];}参考样程。