第7章 分治算法(C++版)
c语言分治法实现合并排序算法

c语言分治法实现合并排序算法分治法是一种重要的算法思想,它将原问题分解成若干个子问题来解决,最终将子问题的解合并为原问题的解。
其中,合并排序算法就是分治法的一个典型应用。
合并排序算法是一种基于比较的排序算法,它将待排序的序列不断地分割成更小的子序列,直到每个子序列只有一个元素为止,然后将这些子序列合并起来,直到整个序列有序为止。
在C语言中,实现合并排序算法的分治法思想非常简单,可以通过递归调用函数来实现。
具体来说,可以将待排序序列分为左右两个子序列,分别对其进行排序,最后将左右两个有序序列进行合并。
下面是C语言实现合并排序算法的示例代码:```void merge(int arr[], int l, int m, int r){int i, j, k;int n1 = m - l + 1;int n2 = r - m;/* 创建临时数组 */int L[n1], R[n2];/* 拷贝数据到临时数组 L[] 和 R[] */for (i = 0; i < n1; i++)L[i] = arr[l + i];for (j = 0; j < n2; j++)R[j] = arr[m + 1 + j];/* 合并临时数组到 arr[l..r]*/i = 0; /* 初始化左子数组的索引 */ j = 0; /* 初始化右子数组的索引 */ k = l; /* 初始归并子数组的索引 */ while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k] = L[i];i++;}else {arr[k] = R[j];j++;}k++;}/* 拷贝 L[] 的剩余元素 */while (i < n1) {arr[k] = L[i];i++;k++;}/* 拷贝 R[] 的剩余元素 */while (j < n2) {arr[k] = R[j];j++;k++;}}void mergeSort(int arr[], int l, int r){if (l < r) {/* 找到中间点 */int m = l + (r - l) / 2;/* 分治排序左子数组和右子数组 */mergeSort(arr, l, m);mergeSort(arr, m + 1, r);/* 合并已排序的左子数组和右子数组 */merge(arr, l, m, r);}}```上述代码中,首先定义了一个函数 `merge()` 用于将两个已排序的子序列合并成一个有序序列。
C语言七大算法

C语言七大算法一、概述算法是计算机程序设计中解决问题的方法和步骤的描述,是计算机科学的重要基础。
在计算机科学中,有许多经典的算法被广泛应用,并成为不可或缺的工具。
本文将介绍C语言中的七大经典算法,包括排序算法、查找算法、图算法、字符串算法、动态规划算法、贪心算法和分治算法。
二、排序算法排序是将一组元素按照特定规则进行重新排列的过程。
常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。
这些排序算法在C语言中都有相应的实现,并且各有特点和适用场景。
三、查找算法查找算法用于在一组数据中查找特定值的位置或判断是否存在。
常见的查找算法有线性查找、二分查找、哈希查找等。
这些算法在C语言中的实现可以帮助我们快速地定位目标值。
四、图算法图算法用于解决与图相关的问题,包括最短路径问题、最小生成树问题、拓扑排序等。
在C语言中,我们可以利用图的邻接矩阵或邻接表来实现相关的图算法。
五、字符串算法字符串算法主要用于解决字符串匹配、替换、拼接等问题。
在C语言中,我们可以使用字符串库函数来完成一些基本的字符串操作,例如字符串比较、复制、连接等。
六、动态规划算法动态规划算法是解决一类最优化问题的常用方法,它将问题分解为多个子问题,并通过保存已解决子问题的结果来避免重复计算。
在C语言中,我们可以使用动态规划算法来解决背包问题、最长公共子序列问题等。
七、贪心算法贪心算法是一种通过每一步的局部最优选择来达到全局最优的方法。
贪心算法通常在解决最优化问题时使用,它快速、简单,并且可以给出近似最优解。
C语言中可以使用贪心算法来解决霍夫曼编码、最小生成树等问题。
八、分治算法分治算法是一种将问题分解为多个相同或类似的子问题然后递归解决的方法。
常见的分治算法有快速排序、归并排序等。
在C语言中,我们可以使用分治算法来提高程序的效率和性能。
总结:本文介绍了C语言中的七大经典算法,包括排序算法、查找算法、图算法、字符串算法、动态规划算法、贪心算法和分治算法。
c语言分治法实现合并排序算法

c语言分治法实现合并排序算法在计算机科学中,分治算法是一种将问题划分为较小子问题,然后将结果合并以解决原始问题的算法。
其中,合并排序算法就是一种常见的分治算法。
C语言可以使用分治法实现合并排序算法。
该算法的基本思想是将原始数组递归地分成两半,直到每个部分只有一个元素,然后将这些部分合并起来,直到形成一个完整的已排序的数组。
具体实现过程如下:1.首先,定义一个函数merge,该函数将两个已排序的数组合并成一个已排序的数组。
2.然后,定义一个函数merge_sort,该函数使用递归的方式将原始数组分成两个部分,并对每个部分调用merge_sort函数以进行排序。
3.最后,将已排序的两个数组合并到一起,使用merge函数。
以下是C语言代码:void merge(int arr[], int left[], int left_count, int right[], int right_count) {int i = 0, j = 0, k = 0;while (i < left_count && j < right_count) {if (left[i] < right[j]) {arr[k++] = left[i++];} else {arr[k++] = right[j++];}}while (i < left_count) {arr[k++] = left[i++];}while (j < right_count) {arr[k++] = right[j++];}}void merge_sort(int arr[], int size) { if (size < 2) {return;}int mid = size / 2;int left[mid];int right[size - mid];for (int i = 0; i < mid; i++) {left[i] = arr[i];}for (int i = mid; i < size; i++) {right[i - mid] = arr[i];}merge_sort(left, mid);merge_sort(right, size - mid);merge(arr, left, mid, right, size - mid);}int main() {int arr[] = {3, 8, 1, 6, 9, 4, 5, 7, 2};int size = sizeof(arr) / sizeof(arr[0]);merge_sort(arr, size);for (int i = 0; i < size; i++) {printf('%d ', arr[i]);}return 0;}以上代码可以将数组{3, 8, 1, 6, 9, 4, 5, 7, 2}排序成{1, 2, 3, 4, 5, 6, 7, 8, 9}。
分治算法

65 97
13 76
38 49 65 97
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归 调用
49 38 65 97 76 13 27
38 49
65 97
13 76
27
38 49 65 97
题的解,自底向上逐步求出原来问题的解。
T(n)
=
n
递归的概念
由分治法产生的子问题往往是原问题的较小模式,这 就为使用递归技术提供了方便。在这种情况下,反复 应用分治手段,可以使子问题与原问题类型一致而其 规模却不断缩小,最终使子问题缩小到很容易直接求 出其解。这自然导致递归过程的产生。
直接或间接地调用自身的算法称为递归算法。用函数 自身给出定义的函数称为递归函数。
黑盒划分典型问题—合并排序
【例5】合并排序
任务描述:任意给定一包含n个整数的集合,把n个整数按升序排列。 输入:每测试用例包括两行,第一行输入整数个数,第二行输入n个整 数,数与数之间用空格隔开。最后一行包含-1,表示输入结束。 输出:每组测试数据的结果输出占一行,输出按升序排列的n个整数。 样例输入:
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归调用 自然合并排序
49 38 65 97 76 13 27
49
38 65 97
76
13 27
38 49 65 97
黑盒划分典型问题—逆序对问题
分治算法矩阵乘法

分治算法矩阵乘法矩阵乘法是一个常见的数学问题,在许多领域都有广泛的应用,包括图形学、物理模拟和机器学习等。
矩阵乘法的传统方法是通过循环遍历两个矩阵的元素并计算乘积。
然而,当矩阵非常大时,这种方法的效率非常低。
此时,分治算法可以提供更快的解决方案。
分治算法是一种将问题分解为更小的子问题并通过组合子问题的解来求解原始问题的方法。
在矩阵乘法问题中,可以将两个大矩阵分解为更小的子矩阵,并通过组合子矩阵的乘积来计算原始矩阵的乘积。
具体地,假设我们要计算两个矩阵A和B的乘积C,其中A是一个m×n的矩阵,B是一个n×p的矩阵。
我们可以将A分解为四个子矩阵:A11、A12、A21和A22,每个子矩阵都是原始矩阵的四分之一大小。
同样地,将矩阵B分解为四个子矩阵:B11、B12、B21和B22根据矩阵乘法的定义,我们可以将C分解为四个子矩阵:C11、C12、C21和C22、根据分治算法的思想,我们可以通过以下步骤计算C的子矩阵:1.计算C11的值:C11=A11*B11+A12*B212.计算C12的值:C12=A11*B12+A12*B223.计算C21的值:C21=A21*B11+A22*B214.计算C22的值:C22=A21*B12+A22*B22通过分解原始矩阵和子矩阵的乘积,我们可以将大问题转化为四个较小的子问题,这些子问题可以并行计算。
然后,通过组合子问题的解来得到原始矩阵的乘积。
为了更好地理解分治算法在矩阵乘法中的应用,我们可以考虑一个具体的例子。
假设我们有两个2×2的矩阵:A=[[1,2],[3,4]]B=[[5,6],[7,8]]根据分治算法的步骤,我们可以将A和B分解为四个子矩阵:A11=[[1]]A12=[[2]]A21=[[3]]A22=[[4]]B11=[[5]]B12=[[6]]B21=[[7]]B22=[[8]]然后,我们可以通过计算子矩阵的乘积来得到C的子矩阵:C11=A11*B11+A12*B21=[[1]]*[[5]]+[[2]]*[[7]]=[[19]]C12=A11*B12+A12*B22=[[1]]*[[6]]+[[2]]*[[8]]=[[22]]C21=A21*B11+A22*B21=[[3]]*[[5]]+[[4]]*[[7]]=[[37]]C22=A21*B12+A22*B22=[[3]]*[[6]]+[[4]]*[[8]]=[[46]]最后,我们可以将子矩阵组合在一起,得到C的最终值:C=[[19,22],[37,46]]通过分治算法,我们将原始矩阵乘法的时间复杂度从O(n^3)降低到O(n^log2(7)),其中n是矩阵的大小。
《算法分治法》课件

分治算法的步骤
分治算法的步骤还包括对问题进行归纳和分类,确定 问题的规模和复杂度,选择合适的分治策略和算法实 现方式等。
单击此处添加正文,文字是您思想的提一一二三四五 六七八九一二三四五六七八九一二三四五六七八九文 ,单击此处添加正文,文字是您思想的提炼,为了最 终呈现发布的良好效果单击此4*25}
分治算法的核心思想是将一个复杂的问题分解为若干个规模较小、相互独立、与 原问题形式相同的子问题,递归地解这些子问题,然后再将子问题的解合并,以 求得原问题的解。
分治算法的原理
分治算法的原理是利用问题的相似性,将大问题分解为小问 题,将复杂问题转化为简单问题,从而降低问题的难度,提 高解决问题的效率。
探索分治算法与其他算法(如贪心算法、动态规划等)的结合
,实现更高效的算法设计。
分治算法的理论基础研究
02
深入探讨分治算法的理论基础,为算法设计和优化提供理论支
持。
分治算法在实际问题中的应用研究
03
针对实际问题,研究分治算法的应用场景和解决方案,推动算
法的实际应用。
THANKS
感谢观看
对于可以并行处理的子问题,可以使 用多线程或分布式计算等技术进行并 行处理,进一步提高算法效率。
动态规划
动态规划是一种常用的优化技术,通 过将子问题存储在表格中并逐步更新 ,可以避免重复计算,提高算法效率 。
分治算法在实际项目中的应用案例
归并排序
归并排序是一种典型的分治算法,通过递归地将数组分解为若干个子数组,然后合并子数 组得到有序数组。在实际应用中,归并排序广泛应用于各种排序场景。
c++分治算法详解
c++分治算法详解《C分治算法详解》分治算法是一种将一个难以直接解决的大问题分解成几个规模较小、相互独立的小问题来解决的思想。
这种算法的核心是将一个大问题分解成两个或多个相似的小问题,然后递归地解决这些小问题,最终将小问题的解决方案合并起来得到大问题的解决方案。
一、分治算法的基本思想分治算法的核心是将一个大问题分解成几个子问题,然后将这些子问题分别解决,最后将子问题的解决方案合并起来得到原问题的解决方案。
这种思想的核心是将一个大问题分解成更小的、更易于解决的问题,从而降低问题的复杂度,提高解决问题的效率。
二、分治算法的步骤1.将原问题分解成两个或多个规模较小、相互独立的小问题;2.递归地解决这些小问题;3.将小问题的解决方案合并起来得到原问题的解决方案。
三、C语言实现分治算法下面是一个使用C语言实现分治算法的示例代码,用于求解一个简单的加法问题:```c#include<stdio.h>voidadd(inta[],intleft,intright){intmid=(left+right)/2;intsub_left=left;intsub_right=right;inti=left;while(i<=mid){if(a[i]>a[mid]){sub_right=mid;i++;}elseif(a[i]<a[mid]){sub_left=i;break;}else{i++;}}printf("Sumof%dand%dis%d\n",a[left],a[mid],a[mid]+(a[sub_ right]-a[sub_left]));add(a,sub_left,sub_right);}```这个程序使用递归的方式将原问题分解成两个子问题,然后分别求解这两个子问题,最后将子问题的解决方案合并起来得到原问题的解决方案。
这个程序的时间复杂度为O(nlogn),其中n为数组的长度。
分治算法实验(用分治法查找数组元素的最大值和最小值)
算法分析与设计实验报告第一次实验附录:完整代码(分治法)#include<iostream>#include<time.h>#include<iomanip>using namespace std;//当数组中的元素个数小于3时,处理最大值int compmax(int A[],int start,int end){int max;if(start<end) //有两个元素{if(A[start]<=A[end])max=A[end];elsemax=A[start];}else//有一个元素max=A[start];return max;}//当数组中元素的个数小于2时,处理最小值int compmin(int A[],int start,int end){int min;if(start<end) //有两个元素{if(A[start]<=A[end])min=A[start];elsemin=A[end];}else//有一个元素min=A[start];return min;}//分治法处理整个数组,求最大值与最小值void merge(int a[],int left,int right,int &Max,int &Min) //Max,Min用来保存最大值与最小值//之所以使用&引用,是由于如果只是简单的使用变量,并不会改变Max与Min的值,使用指针也可以{int max1=0,min1=0,max2=0,min2=0;if(right-left>2) //当数组中元素个数大于等于3时,进行分治{int mid=(right+left)/2;merge(a,left,mid,max1,min1); //左半边递归调用自身,求出最大值最小值,分别保存在max1,min1中merge(a,mid+1,right,max2,min2); //右半边递归调用自身,求出最大值最小值,分别保存在max2,min2中if(max1>=max2) //子序列两两合并,求出最大值与最小值,保存在Max与Min中Max=max1;elseMax=max2;if(min1<=min2)Min=min1;elseMin=min2;}else//数组中元素个数小于3时的情况,直接赋值{Max=compmax(a,left,right);Min=compmin(a,left,right);}}void ran(int *input,int n) //随机生成数组元素函数{int i;srand(time(0));for(i=0;i<n;i++)input[i]=rand();input[i]='\0';}int a[1000000]; //定义全局变量用来存放要查找的数组int main(){int n;int i;int max;int min;cout<<"请输入要查找的序列个数:"<<endl;for(i=0;i<5;i++){cin>>n;ran(a,n);clock_t start,end,over; //计算程序运行时间的算法start=clock();end=clock();over=end-start;start=clock();merge(a,0,n-1,max,min); //调用分治法算法cout<<max<<" "<<min<<endl;end=clock();printf("The time is %6.3f",(double)(end-start-over)/CLK_TCK); //显示运行时间}system("pause"); //停止运行窗口return 0;}完整代码(非递归方法)#include<iostream>#include<time.h>#include<iomanip>using namespace std;void ran(int *input,int n) //随机生成数组元素函数{int i;srand(time(0));for(i=0;i<n;i++)input[i]=rand();input[i]='\0';}int a[1000000];int main(){int max=a[0],min=a[0];int i,j,n;cout<<"请输入数据规模:"<<endl;for(j=0;j<5;j++){cin>>n;ran(a,n);clock_t start,end,over; //计算程序运行时间的算法start=clock();end=clock();over=end-start;start=clock();for(i=1;i<n;i++){if(a[i]>max)max=a[i];if(a[i]<min)min=a[i];}cout<<max<<" "<<min<<endl;end=clock();printf("The time is %6.3f",(double)(end-start-over)/CLK_TCK); //显示运行时间}system("pause");return 0;}。
循环赛日程表分治算法(c语言)
/** 设有n=2k个运动员要进行网球循环赛。
现要设计一个满足以下要求的比赛日程表:* 每个选手必须与其他n-1个选手各赛一次;* 每个选手一天只能参赛一次;* 循环赛在n-1天内结束。
* 数组a[i][j]第i个选手在第j天所遇到的选手。
*/#include<>#include<>~void gametable(int k){int a[100][100];int n,temp,i,j,p,t;n=2;..2^k个选手的比赛日程{temp=n;n=n*2;//填左下角元素for(i=temp+1;i<=n;i++)for(j=1;j<=temp;j++)a[i][j]=a[i-temp][j]+temp;//左下角和左上角元素的对应关系)for(i=1;i<=temp;i++)//将左下角元素抄到右上角for(j=temp+1;j<=n;j++)a[i][j]=a[i+temp][(j+temp)%n];for(i=temp+1;i<=n;i++)//将左上角元素抄到右下角for(j=temp+1;j<=n;j++)a[i][j]=a[i-temp][j-temp];}printf("参赛人数为:%d\n(第i行第j列表示和第i个选手在第j天比赛的选手序号)\n",n);for(i=1;i<=n;i++)\for(j=1;j<=n;j++){printf("%d ",a[i][j]);if(j==n)printf("\n");}}void main()#{int k;printf("比赛选手个数为n(n=2^k),请输入参数K(K>0):\n");scanf("%d",&k);if(k!=0)gametable(k);}。
c++分治算法详解
c++分治算法详解摘要:1.分治算法概述2.C++分治算法实现a.快速排序b.归并排序c.赫夫曼编码3.分治算法的优势和应用4.C++分治算法案例分析a.快速排序案例b.归并排序案例c.赫夫曼编码案例5.总结正文:C++分治算法详解分治算法是一种将大问题分解为若干个相同或相似的小问题,然后逐个解决小问题,最后将小问题的解合并得到大问题的解的算法。
这种算法的设计思想是将一个难以直接解决的问题,分割成一些规模较小的相同问题,以便各个击破。
分治算法广泛应用于计算机科学、数学、物理学等领域,其中快速排序、归并排序、赫夫曼编码等是常见的分治算法。
C++分治算法实现1.快速排序快速排序是一种常用的分治算法,它采用分治策略将待排序的数组划分为较小和较大的两个子数组,然后递归地对子数组进行排序,最终合并得到有序数组。
快速排序的平均时间复杂度为O(nlogn),它有效地提高了排序速度。
2.归并排序归并排序也是一种分治算法,它将待排序的数组划分为较小和较大的两个子数组,然后递归地对子数组进行排序,最后将有序的子数组合并得到有序数组。
归并排序的时间复杂度为O(nlogn),空间复杂度为O(n)。
3.赫夫曼编码赫夫曼编码是一种基于分治思想的压缩算法,它将原始数据分为若干个子数据,然后对子数据进行编码,最后将编码后的子数据合并得到压缩后的数据。
赫夫曼编码能够实现最优压缩,即压缩后的数据长度最短。
分治算法的优势和应用分治算法具有以下优势:1.将大问题分解为小问题,降低问题的复杂度,便于解决。
2.递归地解决小问题,可以减少代码的编写。
3.分治算法可以有效地提高排序速度。
分治算法广泛应用于排序、查找、压缩等领域。
例如,快速排序和归并排序用于对数组进行排序,赫夫曼编码用于数据压缩。
C++分治算法案例分析1.快速排序案例假设有一个长度为10 的数组{5, 2, 9, 1, 5, 6},采用快速排序进行排序。
首先,将数组划分为较小和较大的两个子数组,即{1, 2, 5, 5}和{9, 6}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1 2 3 4 5 6 7 8 2 1 4 3 6 5 8 7 3 4 1 2 7 8 5 6 4 3 2 1 8 7 6 5 5 6 7 8 1 2 3 4 6 5 8 7 2 1 4 3 7 8 5 6 3 4 1 2 8 7 6 5 4 3 2 1 【算法分析】 从八位选手的循环比赛表中可以看出,这是一个具有对称性的方阵,可以把
【问题分析】
以M=3(即N=23=8)为例,可以根据问题要求,制定出如下图所示的 一种方案:
以表格的中心为拆分点,将表格分成A、B、C、D四个部分,就很容易看 出有A=D,B=C,并且,这一规律同样适用于各个更小的部分。 设有n个选手的循环比赛,其中n=2m,要求每名选手要与其他n-1名选手 都赛一次。每名选手每天比赛一次,循环赛共进行n-1天。要求每天没有选手 轮空.以下是八名选手时的循环比赛表,表中第一行为八位选手的编号,下面 七行依次是每位选手每天的对手。
【例1】快速排序(递归算法)
void qsort(int l,int r) { int i,j,mid,p; i=l;j=r; mid=a[(l+r)/2]; //将当前序列在中间位置的数定义为分隔数 do { while (a[i]<mid) {i++;} //在左半部分寻找比中间数大的数 while (a[j]>mid) {j--;} //在右半部分寻找比中间数小的数 if (i<=j) { //若找到一组与排序目标不一致的数对则交换它们 p=a[i];a[i]=a[j];a[j]=p; i++;j--; //继续找 } }while(i<=j); //注意这里要有等号 if (l<j) qsort(l,j); //若未到两个数的边界,则递归搜索左右区间 if (i<r) qsort(i,r); }
【例4】、循环比赛日程表(match) 【问题描述】 设有N个选手进行循环比赛,其中N=2M,要求每名选手
要与其他N-1名选手都赛一次,每名选手每天比赛一次,循 环赛共进行N-1天,要求每天没有选手轮空。 输入:M 输出:表格形式的比赛安排表 【样例输入】match.in 3 【样例输出】match.out 1 2 3 4 5 6 7 8 2 1 4 3 6 5 8 7 3 4 1 2 7 8 5 6 4 3 2 1 8 7 6 5 5 6 7 8 1 2 3 4 6 5 8 7 2 1 4 3 7 8 5 6 3 4 1 2 8 7 6 5 4 3 2 1
第七章 分治算法
所谓分治就是指的分而治之,即将较大规模的问题分解成几个较小规模 的问题,通过对较小规模问题的求解达到对整个问题的求解。当我们将问题分 解成两个较小问题求解时的分治方法称之为二分法。 分治的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这 些子问题互相独立且与原问题相似。找出各部分的解,然后把各部分的解组合 成整个问题的解。 1、解决算法实现的同时,需要估算算法实现所需时间。分治算法时间是 这样确定的: 解决子问题所需的工作总量(由子问题的个数、解决每个子问题的工作量 决定)合并所有子问题所需的工作量。 2、分治法是把任意大小问题尽可能地等分成两个子问题的递归算法。 3、分治的具体过程: {{开始} if ①问题不可分 ②返回问题解 else { ③从原问题中划出含一半运算对象的子问题1; ④递归调用分治法过程,求出解1; ⑤从原问题中划出含另一半运算对象的子问题2; ⑥递归调用分治法过程,求出解2; ⑦将解1、解2组合成整个问题的解; } } //结束
由此得出算法: 输入方程中各项的系数a,b,c,d ; { for (x=-100;x<=100;x++) //枚举每一个可能的根 { x1=x;x2=x+1; //确定根的可能区间 if (f(x1)==0) printf("%.2f ",x1); //若x1为根,则输出 else if (f(x1)*f(x2)<0) //若根在区间[x1,x2]中 { while (x2-x1>=0.001) //若区间[x1,x2]不满足精度要求,则循环 { xx=(x2+x1)/2; //计算区间[x1,x2]的中间位置 if ((f(x1)*f(xx))<=0) //若根在左区间,则调整右指针 x2=xx; else x1=xx; //若根在右区间,则调整左指针 } printf("%.2f ",x1); //区间[x1,x2]满足精度要求,确定x1为根 } } cout<<endl; } double f(double x) //将x代入函数 { return (x*x*x*a+b*x*x+x*c+d); }
2.分治法 枚举根的值域中的每一个整数x(-100≤x≤100)。由于根与根之差的绝 对值≥1,因此设定搜索区间[x1,x2],其中x1=x,x2=x+1。若 ⑴f(x1)=0,则确定x1为f(x)的根; ⑵f(x1)*f(x2)>0,则确定根x不在区间[x1,x2]内,设定[x2,x2+1]为 下一个搜索区间 ⑶f(x1)*f(x2)<0,则确定根x在区间[x1,x2]内。 如果确定根x在区间[x1,x2]内的话(f(x1)*f(x2)<0),如何在该区间 找到根的确切位置。采用二分法,将区间[x1,x2]分成左右两个子区间: 左子区间[x1,x]和右子区间[x,x2](其中x=): 如果f(x1)*f(x)≤0,则确定根在左区间[x1,x]内,将x设为该区间的右 指针(x2=x),继续对左区间进行对分;如果f(x1)*f(x)>0,则确定根在 右区间[x,x2]内,将x设为该区间的左指针(x1=x),继续对右区间进 行对分; 上述对分过程一直进行到区间的间距满足精度要求为止(x2x1<0.001)。此时确定x1为f(x)的根。
方阵一分为四来看,那么左上角的4*4的方阵就是前四位选手的循环比赛表,而 右上角的4*4的方阵就是后四位选手的循环比赛表,它们在本质上是一样的,都 是4个选手的循环比赛表,所不同的只是选手编号不同而已,将左上角中方阵的 所有元素加上4就能得到右上角的方阵.下方的两个方阵表示前四位选手和后四 位选手进行交叉循环比赛的情况,同样具有对称性,将右上角方阵复制到左下角 即得到1,2,3,4四位选手和5,6,7,8四位选手的循环比赛表,根据对称性, 右下角的 方阵应与左上角的方阵相同.这样,八名选手的循环比赛表可以由四名选手的循 环比赛表根据对称性生成出来.同样地, 四名选手的循环比赛表可以由二名选手 的循环比赛表根据对称性生成出来,而两名选手的循环比赛表可以说是已知的, 这种程序设计方法叫做分治法,其基本思想是把一个规模为n的问题分成若干个 规模较小的问题,使得从这些较小问题的解易于构造出整个问题的解。 程序中用数组matchlist记录n名选手的循环比赛表, 整个循环比赛表从最初 的1*1的方阵按上述规则生成出2*2 的方阵, 再生成出4*4 的方阵,……,直到生 成出整个循环比赛表为止.变量half表示当前方阵的大小,也是要生成的下一个 方阵的大小的一半 。
//找到查找的数,输出结果 //找不到该数
//在后半中查找 //在前半中查找
【例3】一元三次方程求解 有形如:ax3+bx2+cx+d=0这样的一个一元三次方程。给出该方程中各项的 系数(a,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在-100至 100之间),且根与根之差的绝对值≥1。 要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精 确到小数点后2位。 提示:记方程f(x)=0,若存在2个数x1和x2,且x1<x2,f(x1)*f(x2)< 0,则在(x1,x2)之间一定有一个根。 输入:a,b,c,d 输出:三个实根(根与根之间留有空格) 【输入输出样例】 输入:1 -5 -4 20 输出:-2.00 2.00 5.00 【算法分析】 这是一道有趣的解方程题。为了便于求解,设方程f(x)=ax3+bx2+cx+d=0, 设根的值域(-100至100之间)中有x, 其左右两边相距0.0005的地方有x1和x2 两个数,即 x1=x-0.0005,x2=x+0.0005。x1和x2间的距离(0.001)满足精度要 求(精确到小数点后2位)。若出现如图1所示的两种情况之一,则确定x为f(x)=0 的根。
有两种方法计算f(x)=0的根x: 1.枚举法 根据根的值域和根与根之间的间距要求(≥1),我们不妨将根的值域扩大100 倍(-10000≤x≤10000),依次枚举该区间的每一个整数值x,并在题目要求的精度 内设定区间:x1=,x2=。若区间端点的函数值f(x1)和f(x2)异号或者在区间端点 x1的函数值f(x1)=0,则确定为f(x)=0的一个根。 由此得出算法: 输入方程中各项的系数a,b,c,d ; for (x=-10000;x<=10000;x++) //枚举当前根*100的可能范围 { x1=(x-0.05)/100;x2=(x+0.05)/100;//在题目要求的精度内设定区间 if (f(x1)*f(x2)<0||f(x1)==0) //若在区间两端的函数值异号或在x1处 的函数值为0,则确定x/100为根 printf(―%.2f‖,x/100); } 其中函数f(x)计算x3+b*x2+c*x+d: double f(double x) //计算x3+b*x2+c*x+d { f=x*x*x+b*x*x+c*x+d; } //f函数
//输入排序好的数
//输入要查找的数 //递归过f (a[k]==m) cout<<"then num in "<<k<<endl; if (x>y) cout<<"no find"<<endl; else { if (a[k]<m) jc(k+1,y); if (a[k]>m) jc(x,k-1); } }