算法设计与分析报告+常用方法
计算机科学算法设计与复杂性分析

计算机科学算法设计与复杂性分析计算机科学算法设计与复杂性分析是计算机科学领域的重要课题。
在计算机科学领域中,算法是解决问题的步骤和方法。
它的设计涉及到问题的建模和解决方案的设计与实现。
在实际应用中,算法的性能和复杂性是评估其优劣的关键因素。
本文将介绍计算机科学中算法设计的基本原则和复杂性分析的方法。
一、算法设计的基本原则在计算机科学中,算法设计的基本原则包括以下几个方面:1. 清晰和明确的问题描述:在设计算法之前,首先需要对问题进行清晰和明确的描述。
问题描述应包括问题的输入和输出,以及问题的约束条件。
2. 模块化和分解:复杂的问题可以通过将其分解为若干个较简单的子问题来进行解决。
模块化的设计思想有助于提高算法的复用性和可维护性。
3. 合适的数据结构选择:选择合适的数据结构对于算法的性能至关重要。
不同的数据结构适用于不同类型的问题,例如数组、链表、栈、队列等。
4. 适当的算法选择:在设计算法时,需要综合考虑算法的时间复杂性和空间复杂性。
有时候,一个简单但时间复杂性较高的算法可能比一个复杂但时间复杂性较低的算法更加合适。
二、复杂性分析的方法复杂性分析是用于评估算法性能的重要方法,常用的复杂性分析方法包括时间复杂性分析和空间复杂性分析。
1. 时间复杂性分析:时间复杂性是衡量算法在执行过程中所需时间的度量。
常用的时间复杂性分析方法有最坏情况分析、平均情况分析和最好情况分析。
最坏情况分析给出了算法在最坏情况下的执行时间上界,平均情况分析则考虑了各种输入情况的概率分布,最好情况分析给出了算法在最理想情况下的执行时间下界。
2. 空间复杂性分析:空间复杂性是衡量算法在执行过程中所需空间的度量。
与时间复杂性类似,空间复杂性也可以进行最坏情况分析、平均情况分析和最好情况分析。
通常情况下,空间复杂性主要考虑算法所需的额外空间。
三、算法设计与复杂性分析的应用举例为了更好地理解算法设计与复杂性分析的具体应用,下面将介绍两个与计算机科学相关的实际问题。
《算法设计与分析》实验报告实验一...

《算法设计与分析》实验报告实验一递归与分治策略应用基础学号:**************姓名:*************班级:*************日期:2014-2015学年第1学期第九周一、实验目的1、理解递归的概念和分治法的基本思想2、了解适用递归与分治策略的问题类型,并能设计相应的分治策略算法3、掌握递归与分治算法时间空间复杂度分析,以及问题复杂性分析方法二、实验内容任务:以下题目要求应用递归与分治策略设计解决方案,本次实验成绩按百分制计,完成各小题的得分如下,每小题要求算法描述准确且程序运行正确。
1、求n个元素的全排。
(30分)2、解决一个2k*2k的特殊棋牌上的L型骨牌覆盖问题。
(30分)3、设有n=2k个运动员要进行网球循环赛。
设计一个满足要求的比赛日程表。
(40分)提交结果:算法设计分析思路、源代码及其分析说明和测试运行报告。
三、设计分析四、算法描述及程序五、测试与分析六、实验总结与体会#include "iostream"using namespace std;#define N 100void Perm(int* list, int k, int m){if (k == m){for (int i=0; i<m; i++)cout << list[i] << " ";cout << endl;return;}else{for (int i=m; i<k; i++){swap(list[m], list[i]);Perm(list, k, m+1);swap(list[m], list[i]);}}}void swap(int a,int b){int temp;temp=a;a=b;b=temp;}int main(){int i,n;int a[N];cout<<"请输入排列数据总个数:";cin>>n;cout<<"请输入数据:";for(i=0;i<n;i++){cin>>a[i];}cout<<"该数据的全排列:"<<endl;Perm(a,n,0);return 0;}《算法设计与分析》实验报告实验二递归与分治策略应用提高学号:**************姓名:*************班级:*************日期:2014-2015学年第1学期一、实验目的1、深入理解递归的概念和分治法的基本思想2、正确使用递归与分治策略设计相应的问题的算法3、掌握递归与分治算法时间空间复杂度分析,以及问题复杂性分析方法二、实验内容任务:从以下题目中任选一题完成,要求应用递归与分治策略设计解决方案。
南京邮电大学算法分析与设计实验报告——密码算法

实验报告(2013/2014学年第一学期)课程名称算法分析与设计实验名称密码算法实验时间2014 年 5 月23 日指导单位计算机学院软件工程系指导教师张怡婷学生姓名班级学号B******** 学院(系) 软件工程专业软件工程实验报告三、实验原理及内容(包括操作过程、结果分析等)实验步骤1、RSA 算法是由麻省理工学院的Ron Rivest,Adi Shamir 和Len Adleman 于1977 年研制并于1978 年首次发表的一种算法,是第一个能同时用于加密和数字签名的算法,且易于理解和操作,因此作为一种通用公开密钥加密方式而受到推崇。
RSA 是一种分组密码,其中明文和密文都是小于某个n 的从0 到n-1 的整数,则分组的二进制值长度必须小于或等于log2n。
若以M 表示明文分组,而C 表示密文分组,则加密和解密的过程如下:C=Me mod nM=Cd mod n=(Me)d mod n=Med mod n发送方和接受方都必须知道n 的值。
发送方知道 e 的值,而只有接受方知道d 的值。
因此这是一种公开密钥为{e,n},且私有密钥为{d,n}的公开密钥加密算法。
此时算法要能够满足公开密钥加密的要求,则必须满足以下条件:(1)有可能找到e、d、n 的值,使得对所有M<n 有Med=M mod n。
(2)对于所有M<n 的值,要计算Me和Cd 相对来说是简单的。
(3)在给定e 和n 时,判断出 d 是不可行的。
2、重点考虑第一个条件:由Euler 定理的一个推论:给定两个素数p和q以及两个整数n 和m,使得n=pq 而且0<m<n,并且对于任意整数k,下列关系成立:mkΦ(n)+1=mk(p-1)(q-1)+1≡m mod n其中Φ(n)是欧拉函数,也就是不超过n 且与n 互素的整数个数。
对于素数p 和q,有Φ(pq)=(p-1)(q-1)。
因此得到需要的关系:ed=kΦ(n)+1,等价于: ed≡1 mod Φ(n)d≡e-1 mod Φ(n)也就是说:d 和 e 是以Φ(n)为模的乘法逆元。
数值计算中的算法设计与理论分析

数值计算中的算法设计与理论分析在现代科学和技术的发展中,数值计算是一个不可或缺的工具。
它将数学理论应用于工程、科学与社会经济等领域,为我们提供了各种各样的数值计算方法。
在数值计算中,算法设计是一个至关重要的环节,而算法的效率、稳定性和可靠性则与其理论分析密不可分。
一、数值计算中的算法设计算法设计是数值计算的核心,其设计目标通常是快速和准确地解决问题。
不同的问题需要不同的算法设计,常用的算法包括迭代法、插值法、微分方程数值解法、统计学方法等。
1. 迭代法迭代法是一种求解方程组或者函数零点的方法。
该方法的基本思想是从一个初值开始,不断迭代逼近目标解。
迭代法通常有牛顿迭代法、割线法等,其中牛顿迭代法是一种高效且广泛使用的方法,具有收敛速度快、收敛性好等优点,常用于求解非线性问题。
例如,求解方程f(x) = 0,其中f(x)是一个连续可导函数。
由泰勒展开可知,在x处的一次近似为:f(x + h) ≈ f(x) + hf'(x)设此时函数的近似根为x1,根据近似式有:0 ≈ f(x1 + h) ≈ f(x1) + hf'(x1)可得:x1 ≈ x - f(x)/f'(x)这就是牛顿迭代法的基本思路。
2. 插值法插值法是通过已知的有限个点来推算出未知数在某些位置处的数值。
插值法包括拉格朗日插值法、牛顿插值法、分段插值法等,其中最常用的是拉格朗日插值法和牛顿插值法。
例如,给定函数f(x)在点x0, x1, ..., xn处的取值yi = f(xi),要求在区间[x0, xn]内的任意点x处的函数值f(x)。
对于插值点xi,求相应的插值函数L(x),则L(x)的表达式为:L(x) = Σfi*li(x)其中fi是插值点xi对应的函数值,li(x)是插值点xi对应的基函数。
3. 微分方程数值解法微分方程数值解法是求解微分方程问题的一种数值计算方法。
常用的数值解法有欧拉法、龙格-库塔法、后向欧拉法等。
防碰撞算法的实验设计与数据分析方法

防碰撞算法的实验设计与数据分析方法引言:随着无人驾驶技术的快速发展,防碰撞算法成为了关注的焦点。
防碰撞算法的设计和优化对于无人驾驶的安全性至关重要。
本文将探讨防碰撞算法的实验设计与数据分析方法,以期为相关研究提供一些指导。
一、实验设计1. 确定实验目标:在进行防碰撞算法的实验设计之前,首先要明确实验的目标。
例如,我们可以以最小化碰撞风险为目标,或者以最大化避让效果为目标。
2. 确定实验场景:根据实验目标,选择合适的实验场景。
可以考虑不同的道路类型、车辆密度、天气条件等因素。
同时,还可以考虑加入一些特殊情况,如突然出现的障碍物或者紧急制动等。
3. 设计实验参数:根据实验目标和实验场景,设计合适的实验参数。
例如,可以调整车辆速度、跟车距离、制动响应时间等参数。
通过调整这些参数,可以模拟不同的驾驶行为和交通情况。
4. 确定实验指标:根据实验目标,选择合适的实验指标。
例如,可以以碰撞率、避让成功率、制动响应时间等指标来评估算法的性能。
同时,还可以考虑使用一些更具体的指标,如避让路径长度、避让轨迹的平滑度等。
二、数据采集与处理1. 选择合适的传感器:在进行实验数据采集时,选择合适的传感器非常重要。
常用的传感器包括激光雷达、摄像头、超声波传感器等。
根据实验场景和实验目标,选择适合的传感器来获取相关数据。
2. 数据采集:在进行实验数据采集时,需要确保数据的准确性和完整性。
可以使用多个传感器进行数据采集,以获得更全面的信息。
同时,还可以考虑使用多个车辆进行实验,以增加数据的多样性。
3. 数据处理:在进行数据分析之前,需要对采集到的数据进行处理。
可以使用滤波算法、噪声去除算法等对数据进行预处理。
同时,还可以考虑使用机器学习算法对数据进行分类和聚类,以发现隐藏在数据中的规律。
三、数据分析方法1. 统计分析:可以使用统计方法对数据进行分析。
例如,可以计算碰撞率、避让成功率的平均值和方差,以评估算法的性能。
同时,还可以使用假设检验等方法来验证实验结果的可靠性。
武汉理工大学算法分析实验报告

学生实验报告书实验课程名称算法设计与分析开课学院计算机科学与技术学院指导教师姓名李晓红学生姓名学生专业班级软件工程zy1302班2015-- 2016学年第一学期实验课程名称:算法设计与分析同组者实验日期2015年10月20日第一部分:实验分析与设计一.实验内容描述(问题域描述)1、利用分治法,写一个快速排序的递归算法,并利用任何一种语言,在计算机上实现,同时进行时间复杂性分析;2、要求用递归的方法实现。
二.实验基本原理与设计(包括实验方案设计,实验手段的确定,试验步骤等,用硬件逻辑或者算法描述)本次的解法使用的是“三向切分的快速排序”,它是快速排序的一种优化版本。
不仅利用了分治法和递归实现,而且对于存在大量重复元素的数组,它的效率比快速排序基本版高得多。
它从左到右遍历数组一次,维护一个指针lt使得a[lo..lt-1]中的元素都小于v,一个指针gt 使得a[gt+1..hi]中的元素都大于v,一个指针i使得a[lt..i-1]中的元素都等于v,a[i..gt]中的元素都还未确定,如下图所示:public class Quick3way{public static void sort(Comparable[] a, int lo, int hi){if (lo >= hi)return;int lt = lo, i = lo + 1, gt = hi;Comparable pivot = a[lo];第二部分:实验调试与结果分析一、调试过程(包括调试方法描述、实验数据记录,实验现象记录,实验过程发现的问题等)1、调试方法描述:对程序入口进行断点,随着程序的运行,一步一步的调试,得到运行轨迹;2、实验数据:"R", "B", "W", "W", "R", "W", "B", "R", "R", "W", "B", "R";3、实验现象:4、实验过程中发现的问题:(1)边界问题:在设计快速排序的代码时要非常小心,因为其中包含非常关键的边界问题,例如:什么时候跳出while循环,递归什么时候结束,是对指针的左半部分还是右半部分排序等等;(2)程序的调试跳转:在调试过程中要时刻记住程序是对那一部分进行排序,当完成了这部分的排序后,会跳到哪里又去对另外的那一部分进行排序,这些都是要了然于心的,这样才能准确的定位程序。
体育比赛算法设计与数据分析
体育比赛算法设计与数据分析体育比赛是社会上普遍存在的竞技活动形式,它让运动员和粉丝们体验到了激烈的比赛氛围和刺激的胜利喜悦。
目前,随着计算机技术和数据分析技术的飞速发展,这些比赛也有了新的面貌。
而“体育比赛算法设计与数据分析”技术就是新时代下,比赛胜负判断的核心所在。
一、算法设计算法是指通过一定的计算规则和方法,让计算机能够模拟人的思考过程来实现特定的计算目的。
对于体育比赛来说,算法设计得好坏直接影响着比赛结果的公正性和精准性。
常见的体育比赛算法包括:1. 积分算法积分算法是最常见的比赛判断方法,它通过赛季中对各支参赛队伍之间的比分进行加减来计算出各队伍的积分。
在此基础上,通常设计了一定的评判标准和排名准则,来确定哪些队伍可以晋级比赛、哪些可以得到奖项等。
2. 进球差排名算法进球差排名算法是针对足球比赛设计的算法。
在这种算法中,对于两支球队,在胜败相同的情况下,比分高的球队将会获得更高的排名,而且进球差也会作为球队排名的决定因素。
3. 实时比分算法随着移动互联网技术的发展,实时比分算法已经成为了体育比赛中新的核心算法之一。
实时比分算法通过计算机程序,将比赛场上发生的所有数据,例如进球、角球、任意球等等,实时准确地传送到观众端上。
这使得粉丝们能够及时而且精准地掌握比赛的进展情况,增加了比赛的趣味性和悬疑性。
二、数据分析与算法设计相辅相成的是数据分析技术。
数据分析是指通过对各种数据采集和处理,来实现对体育比赛的重要信息进行自动化分析和预测的技术。
常见的体育比赛数据分析技术包括:1. 视频技术视频技术是对比赛进行实时跟踪和记录的一种不可或缺的技术。
随着技术的不断提升和发展,视频技术在体育比赛数据分析中所扮演的角色越来越重要。
基于视频技术的数据分析能够精确地捕捉偏差和舞弊行为等异常情况,为比赛的公正性提供了有力的保障。
2. 大数据挖掘大数据挖掘是体育比赛数据分析的前沿技术之一。
它可以通过采集比赛相关的大量数据,比如球员平均射门数、场均任意球效率等,来掌握每个球员或者每个队伍的特征。
算法分析与设计实验报告合并排序快速排序
算法分析与设计实验报告:合并排序与快速排序一、引言算法是计算机科学中非常重要的一部分,它涉及到解决问题的方法和步骤。
合并排序和快速排序是两种经典而常用的排序算法。
本文将对这两种排序算法进行分析和设计实验,通过对比它们的性能和效率,以期得出最优算法。
二、合并排序合并排序是一种分治算法,它将原始数组不断分解为更小的数组,直到最后细分为单个元素。
然后,再将这些单个元素两两合并,形成一个有序数组。
合并排序的核心操作是合并两个有序的数组。
1. 算法步骤(1)将原始数组分解为更小的子数组,直到每个子数组只有一个元素;(2)两两合并相邻的子数组,同时进行排序,生成新的有序数组;(3)重复步骤(2),直到生成最终的有序数组。
2. 算法性能合并排序的最优时间复杂度为O(nlogn),其中n为待排序数组的长度。
无论最好情况还是最坏情况,合并排序的复杂度都相同。
合并排序需要额外的存储空间来存储临时数组,所以空间复杂度为O(n)。
三、快速排序快速排序也是一种分治算法,它将原始数组根据一个主元(pivot)分成两个子数组,一个子数组的元素都小于主元,另一个子数组的元素都大于主元。
然后,递归地对这两个子数组进行排序,最后得到有序数组。
快速排序的核心操作是划分。
1. 算法步骤(1)选择一个主元(pivot),可以是随机选择或者固定选择第一个元素;(2)将原始数组根据主元划分为两个子数组,一个子数组的元素都小于主元,另一个子数组的元素都大于主元;(3)递归地对这两个子数组进行快速排序;(4)重复步骤(2)和(3),直到每个子数组只有一个元素,即得到最终的有序数组。
2. 算法性能快速排序的平均时间复杂度为O(nlogn),其中n为待排序数组的长度。
最坏情况下,当每次选择的主元都是最小或最大元素时,时间复杂度为O(n^2)。
快速排序是原地排序,不需要额外的存储空间,所以空间复杂度为O(1)。
四、实验设计为了验证合并排序和快速排序的性能和效率,我们设计以下实验:1. 实验目的:比较合并排序和快速排序的时间复杂度和空间复杂度。
算法设计与分析实验报告
算法设计与分析实验报告实验一全排列、快速排序【实验目的】1. 掌握全排列的递归算法。
2. 了解快速排序的分治算法思想。
【实验原理】一、全排列全排列的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。
任何n个字符集的排列都可以与1~n的n个数字的排列一一对应,因此在此就以n 个数字的排列为例说明排列的生成法。
n个字符的全体排列之间存在一个确定的线性顺序关系。
所有的排列中除最后一个排列外,都有一个后继;除第一个排列外,都有一个前驱。
每个排列的后继都可以从它的前驱经过最少的变化而得到,全排列的生成算法就是从第一个排列开始逐个生成所有的排列的方法。
二、快速排序快速排序(Quicksort)是对冒泡排序的一种改进。
它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
【实验内容】1.全排列递归算法的实现。
2.快速排序分治算法的实现。
【实验结果】1. 全排列:2. 快速排序:实验二最长公共子序列、活动安排问题【实验目的】1. 了解动态规划算法设计思想,运用动态规划算法实现最长公共子序列问题。
2. 了解贪心算法思想,运用贪心算法设计思想实现活动安排问题。
【实验原理】一、动态规划法解最长公共子序列设序列X=和Y=的一个最长公共子序列Z=,则:i. 若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;ii. 若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;iii. 若xm≠yn且z k≠yn ,则Z是X和Yn-1的最长公共子序列。
其中Xm-1=,Yn-1=,Zk-1=。
最长公共子序列问题具有最优子结构性质。
由最长公共子序列问题的最优子结构性质可知,要找出X=和Y=的最长公共子序列,可按以下方式递归地进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的一个最长公共子序列。
算法设计与分析——输油管道问题实验报告
题目: 输油管道问题学号0091313000913133学生姓名张一楠朱玉婷专业(班级)09计本1班设计题目输油管道问题设计技术参数系统平台:windows 7开发工具:Microsoft Visual C++ 6.0设计要求1.掌握问题分析的方法与步骤,选择合适的方法解决问题。
2.选择合适的算法编写程序。
工作计划1:熟悉题目并理解,及找寻相关资料。
2:根据题目设计并分析算法。
3:使用Visual C++实现。
4:完成设计报告参考资料吕国英.《算法设计与分析》.北京:清华大学出版社,2009摘要本实验,我们通过综合应用算法解决了实际生活中的输油管道问题,通过比较各种算法的时间复杂度以及解决效率,采用了算法中以分治法为基础的随机划分来解决问题,利用随机选择方法找到各个油井的中位数,通过讨论论证了中位数即最优管道位置。
信息奥赛中一个问题有多个算法解决,通过比较不同算法解决问题的效率,选择最高效的一个。
在输油管道问题这个实验中得到运用。
关键词:算法设计,分治法,随机划分,随机选择,中位数目录1 需求分析.............................................................................. 错误!未定义书签。
1.1 实验内容.................................................................... 错误!未定义书签。
1.2 系统的基本逻辑模型 ....................................................... 错误!未定义书签。
1.3 确定目标系统的功能 (5)2 总体设计............................................................................. 错误!未定义书签。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
常用算法设计方法要使计算机能完成人们预定的工作,首先必须为如何完成预定的工作设计一个算法,然后再根据算法编写程序。
计算机程序要对问题的每个对象和处理规则给出正确详尽的描述,其中程序的数据结构和变量用来描述问题的对象,程序结构、函数和语句用来描述问题的算法。
算法数据结构是程序的两个重要方面。
算法是问题求解过程的精确描述,一个算法由有限条可完全机械地执行的、有确定结果的指令组成。
指令正确地描述了要完成的任务和它们被执行的顺序。
计算机按算法指令所描述的顺序执行算法的指令能在有限的步骤内终止,或终止于给出问题的解,或终止于指出问题对此输入数据无解。
通常求解一个问题可能会有多种算法可供选择,选择的主要标准是算法的正确性和可靠性,简单性和易理解性。
其次是算法所需要的存储空间少和执行更快等。
算法设计是一件非常困难的工作,经常采用的算法设计技术主要有迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法等等。
另外,为了更简洁的形式设计和藐视算法,在算法设计时又常常采用递归技术,用递归描述算法。
一、迭代法迭代法是用于求方程或方程组近似根的一种常用的算法设计方法。
设方程为f(x)=0,用某种数学方法导出等价的形式x=g(x),然后按以下步骤执行:(1)选一个方程的近似根,赋给变量x0;(2)将x0的值保存于变量x1,然后计算g(x1),并将结果存于变量x0;(3)当x0与x1的差的绝对值还小于指定的精度要求时,重复步骤(2)的计算。
若方程有根,并且用上述方法计算出来的近似根序列收敛,则按上述方法求得的x0就认为是方程的根。
上述算法用C程序的形式表示为:【算法】迭代法求方程的根{ x0=初始近似根;do {x1=x0;x0=g(x1);/*按特定的方程计算新的近似根*/} while ( fabs(x0-x1)>Epsilon);printf(“方程的近似根是%f\n”,x0);}迭代算法也常用于求方程组的根,令X=(x0,x1,…,x n-1)设方程组为:x i=g i(X) (I=0,1,…,n-1)则求方程组根的迭代算法可描述如下:【算法】迭代法求方程组的根{ for (i=0;i<n;i++)x[i]=初始近似根;do {for (i=0;i<n;i++)y[i]=x[i];for (i=0;i<n;i++)x[i]=gi(X);for (delta=0.0,i=0;i<n;i++)if (fabs(y[i]-x[i])>delta) delta=fabs(y[i]-x[i]);} while (delta>Epsilon);for (i=0;i<n;i++)printf(“变量x[%d]的近似根是 %f”,I,x[i]);printf(“\n”);}具体使用迭代法求根时应注意以下两种可能发生的情况:(1)如果方程无解,算法求出的近似根序列就不会收敛,迭代过程会变成死循环,因此在使用迭代算法前应先考察方程是否有解,并在程序中对迭代的次数给予限制;(2)方程虽然有解,但迭代公式选择不当,或迭代的初始近似根选择不合理,也会导致迭代失败。
二、穷举搜索法穷举搜索法是对可能是解的众多候选解按某种顺序进行逐一枚举和检验,并从中找出那些符合要求的候选解作为问题的解。
【问题】将A、B、C、D、E、F这六个变量排成如图所示的三角形,这六个变量分别取[1,6]上的整数,且均不相同。
求使三角形三条边上的变量之和相等的全部解。
如图就是一个解。
程序引入变量a、b、c、d、e、f,并让它们分别顺序取1至6的证书,在它们互不相同的条件下,测试由它们排成的如图所示的三角形三条边上的变量之和是否相等,如相等即为一种满足要求的排列,把它们输出。
当这些变量取尽所有的组合后,程序就可得到全部可能的解。
细节见下面的程序。
【程序1】# include <stdio.h>void main(){ int a,b,c,d,e,f;for (a=1;a<=6;a++)for (b=1;b<=6;b++){if (b==a) continue;for (c=1;c<=6;c++){if (c==a)||(c==b) continue;for (d=1;d<=6;d++) {if (d==a)||(d==b)||(d==c) continue;for (e=1;e<=6;e++) {if (e==a)||(e==b)||(e==c)||(e==d) continue;f=21-(a+b+c+d+e);if ((a+b+c==c+d+e))&&(a+b+c==e+f+a)) {printf(“%6d,a);printf(“%4d%4d”,b,f);printf(“%2d%4d%4d”,c,d,e);scanf(“%*c”);}}}}}}按穷举法编写的程序通常不能适应变化的情况。
如问题改成有9个变量排成三角形,每条边有4个变量的情况,程序的循环重数就要相应改变。
对一组数穷尽所有排列,还有更直接的方法。
将一个排列看作一个长整数,则所有排列对应着一组整数。
将这组整数按从小到大的顺序排列排成一个整数,从对应最小的整数开始。
按数列的递增顺序逐一列举每个排列对应的每个整数,这能更有效地完成排列的穷举。
从一个排列找出对应数列的下一个排列可在当前排列的基础上作部分调整来实现。
倘若当前排列为1,2,4,6,5,3,并令其对应的长整数为124653。
要寻找比长整数124653更大的排列,可从该排列的最后一个数字顺序向前逐位考察,当发现排列中的某个数字比它前一个数字大时,如本例中的6比它的前一位数字4大,这说明还有对应更大整数的排列。
但为了顺序从小到大列举出所有的排列,不能立即调整得太大,如本例中将数字6与数字4交换得到的排列126453就不是排列124653的下一个排列。
为了得到排列124653的下一个排列,应从已经考察过的那部分数字中选出比数字大,但又是它们中最小的那一个数字,比如数字5,与数字4交换。
该数字也是从后向前考察过程中第一个比4大的数字。
5与4交换后,得到排列125643。
在前面数字1,2,5固定的情况下,还应选择对应最小整数的那个排列,为此还需将后面那部分数字的排列顺序颠倒,如将数字6,4,3的排列顺序颠倒,得到排列1,2,5,3,4,6,这才是排列1,2,4,6,5,3的下一个排列。
按以上想法编写的程序如下。
【程序2】# include <stdio.h># define SIDE_N 3# define LENGTH 3# define VARIABLES 6int A,B,C,D,E,F;int *pt[]={&A,&B,&C,&D,&E,&F};int *side[SIDE_N][LENGTH]={&A,&B,&C,&C,&D,&E,&E,&F,&A};int side_total[SIDE_N];main{}{ int i,j,t,equal;for (j=0;j<VARIABLES;j++)*pt[j]=j+1;while(1){ for (i=0;i<SIDE_N;i++){ for (t=j=0;j<LENGTH;j++)t+=*side[i][j];side_total[i]=t;}for (equal=1,i=0;equal&&i<SIDE_N-1;i++)if (side_total[i]!=side_total[i+1] equal=0;if (equal){ for (i=1;i<VARIABLES;i++)printf(“%4d”,*pt[i]);printf(“\n”);scanf(“%*c”);}for (j=VARIABLES-1;j>0;j--)if (*pt[j]>*pt[j-1]) break;if (j==0) break;for (i=VARIABLES-1;i>=j;i--)if (*pt[i]>*pt[i-1]) break;t=*pt[j-1];* pt[j-1] =* pt[i]; *pt[i]=t;for (i=VARIABLES-1;i>j;i--,j++){ t=*pt[j]; *pt[j] =* pt[i]; *pt[i]=t; }}}从上述问题解决的方法中,最重要的因素就是确定某种方法来确定所有的候选解。
下面再用一个示例来加以说明。
【问题】背包问题问题描述:有不同价值、不同重量的物品n件,求从这n件物品中选取一部分物品的选择方案,使选中物品的总重量不超过指定的限制重量,但选中物品的价值之和最大。
设n个物品的重量和价值分别存储于数组w[ ]和v[ ]中,限制重量为tw。
考虑一个n 元组(x0,x1,…,x n-1),其中x i=0 表示第i个物品没有选取,而x i=1则表示第i个物品被选取。
显然这个n元组等价于一个选择方案。
用枚举法解决背包问题,需要枚举所有的选取方案,而根据上述方法,我们只要枚举所有的n元组,就可以得到问题的解。
显然,每个分量取值为0或1的n元组的个数共为2n个。
而每个n元组其实对应了一个长度为n的二进制数,且这些二进制数的取值范围为0~2n-1。
因此,如果把0~2n-1分别转化为相应的二进制数,则可以得到我们所需要的2n个n元组。
【算法】maxv=0;for (i=0;i<2n;i++){ B[0..n-1]=0;把i转化为二进制数,存储于数组B中;temp_w=0;temp_v=0;for (j=0;j<n;j++){ if (B[j]==1){ temp_w=temp_w+w[j];temp_v=temp_v+v[j];}if ((temp_w<=tw)&&(temp_v>maxv)){ maxv=temp_v;保存该B数组;}}}三、递推法递推法是利用问题本身所具有的一种递推关系求问题解的一种方法。
设要求问题规模为N的解,当N=1时,解或为已知,或能非常方便地得到解。
能采用递推法构造算法的问题有重要的递推性质,即当得到问题规模为i-1的解后,由问题的递推性质,能从已求得的规模为1,2,…,i-1的一系列解,构造出问题规模为I的解。
这样,程序可从i=0或i=1出发,重复地,由已知至i-1规模的解,通过递推,获得规模为i的解,直至得到规模为N的解。
【问题】阶乘计算问题描述:编写程序,对给定的n(n≦100),计算并输出k的阶乘k!(k=1,2,…,n)的全部有效数字。