0
点赞
收藏
分享

微信扫一扫

分治算法总结

_铁马冰河_ 2022-04-03 阅读 104
c++算法

分治思想就是将大规模的问题分解成几个小规模的问题,通过求解这些小规模的问题最后完成对大规模问题的求解,其中,将问题分解成两个小问题求解时的分治方法叫做二分法。(使用二分法的重要前提是有序性)

能够用分治法解决的问题一般都能分解成多个小问题;这几个小问题一般互相独立(如果这些小问题有重合的解一般更适合用动态规划);且通过求出这些小问题的解能合并出大问题的解(这条是能否使用分治法的关键)。

此外,分治法常常用到递归,并且也是归并排序、快速排序等的重要基础。

列举例题理解分治思想

1.找数

描述:

给一个长度为n的单调递增序列的正整数序列,即序列中每一个数都比前一个数大。有m个询问,每次询问一个x,问序列中最后一个小于等于x的数是什么

输入

第一行两个整数n,m

接下来一行n个数,表示这个序列

接下来m行每行一个数,表示一个询问

输出

共m行,表示序列中最后一个小于等于x的数是什么。假如没有,则输出-1。

样例输入:

5 3

1 2 3 4 6

5

1

3

样例输出

4

1

3

分析:

用left表示询问区间的左边界,right询问区间的右边界。起初left=1,right=n,每一次二分取中间值,判断中间值与x的关系,如果中间值大于x,取[left,中间值-1],如果中间值小于等于x,取[中间值+1,right],重复操作直到left>right。

代码:

#include<bits/stdc++.h> 
using namespace std;
int main()
{
int n,m,x,a[110000],mid;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
a[0]=-1;
for(int i=1;i<=m;i++)
{
int left=1,right=n;
cin>>x;
while(left<=right)
{
mid=(left+right)/2;
if(a[mid]<=x)
left=mid+1;
else
right=mid-1;
}
cout<<a[right]<<endl;
}
    return 0;
}

 

2.一元三次方程求解

题目描述
有形如: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)之间一定有一个根。

输入描述:
一行,4个实数A,B,C,D。
输出描述:
一行,3个实根,并精确到小数点后2位。
示例1

输入
复制1 -5 -4 20
输出
-2.00 2.00 5.00

分析:

枚举根的值域中的每一个整数x(-100<=x<=100)由于根与根之差的绝对值>=1,因此设定搜索区间[x1,x2],其中x1=x,x2=x+1,f(x1)=0则x1为根,若f(x1)*f(x2)>0则根不在该区间范围内,找下一个区间,若f(x1)*f(x2)<0,则根x在该区间内。设mid=(x1+x2)/2,用二分法在[x1,x]和[x,x2]寻找根即可.

代码:

#include<bits/stdc++.h>
using namespace std;
double a,b,c,d;
double f(double x)
{
return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
double x,x1,x2,xx;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
for (x=-100;x<=100;x+=1)
{ 
x1=x;x2=x+1;
if(f(x1)==0) printf("%.2f ",x1);
else if (f(x1)*f(x2)<0)
{
while (x2-x1>=0.001)
{
xx=(x1+x2)/2;
if((f(x1)*f(xx))<=0)
x2=xx;
else x1=xx;
}
printf("%.2f ",x1);
}
}
return 0;
}

 

 

 

 

 

 

 

举报

相关推荐

0 条评论