当前位置:   article > 正文

【分治法】典型题目示例、含详细注释_分治法常见练习题

分治法常见练习题

 一、众数问题:

1.众数问题

问题描述:

  给定含有n 个元素的多重集合S,每个元素在S 中出现的次数称为该元素的重数。多重集S 中重数最大的元素称为众数。

  

例如,S={1,2,2,2,3,5}。

多重集S 的众数是2,其重数为3。

编程任务:

  对于给定的由n 个自然数组成的多重集S,编程计算S 的众数及其重数。

数据输入:

  输入数据由文件名为input.txt 的文本文件提供。文件的第1 行多重集S 中元素个数n;接下来的n 行中,每行有一个自然数。

结果输出:

  程序运行结束时,将计算结果输出到文件output.txt 中。输出文件有2 行,第1 行给出众数,第2 行是重数。

输入文件示例          输出文件示例

input.txt             output.txt

6                      2

1                      3

2

2

2

3

5

代码如下: 

  1. #include <iostream>
  2. #include <algorithm>//sort()函数头文件
  3. using namespace std;
  4. #define N 10000
  5. bool cmp(int a,int b){
  6. return a<b;
  7. }
  8. int MaxNum=0; //存储众数大小
  9. int MaxNumCount=0; //存储众数个数
  10. int num[10000];
  11. void split(int left,int right){
  12. if (left >=right) return;//越界跳出
  13. int FirstLeft=left;//记录初始最左侧
  14. int FirstRight=right;//记录初始最右侧
  15. int mid=(left+right)/2;
  16. for(;left<mid &&num[left]!=num[mid];left++);//找到中位数的左临界
  17. for(;right>mid&&num[right]!=num[mid];right--);//找到中位数的右临界
  18. if(MaxNumCount<right-left+1){MaxNum=num[mid];MaxNumCount=right-left+1;}
  19. //若此中位数个数大于众数个数,则更新
  20. //若中位数左临界左边数字个数小于众数个数,则不需要执行下述操作;中位数右临界数字亦然
  21. if(left-FirstLeft>MaxNumCount )split(FirstLeft,left-1);
  22. if(FirstRight-right>MaxNumCount)split(right+1,FirstRight);
  23. }
  24. int main()
  25. {
  26. int n;cin>>n;
  27. for(int i=0;i<n;i++){
  28. cin>>num[i];
  29. }
  30. sort(num,num+n,cmp);//将数组从小到大排序
  31. int left0=0;int right0=n-1;
  32. split(left0,right0);
  33. cout<<MaxNum<<endl;
  34. cout<<MaxNumCount<<endl;
  35. return 0;
  36. }

二、邮局选址问题

2.邮局选址问题

问题描述:

  在一个按照东西和南北方向划分成规整街区的城市里,n 个居民点散乱地分布在不同的街区中。用x 坐标表示东西向,用y 坐标表示南北向。各居民点的位置可以由坐标(x,y) 表示。街区中任意2 点(x1,y1) 和(x2,y2) 之间的距离可以用数值|x1-x2|+|y1-y2| 度量。

居民们希望在城市中选择建立邮局的最佳位置,使n 个居民点到邮局的距离总和最小。

编程任务:

  给定n 个居民点的位置,编程计算n 个居民点到邮局的距离总和的最小值。

数据输入:

  由文件input.txt 提供输入数据。文件的第1 行是居民点数n,1<=n<=10000。接下来n 行是居民点的位置,每行2 个整数x 和y,-10000<=x,y<=10000。

结果输出:

  程序运行结束时,将计算结果输出到文件output.txt 中。文件的第1 行中的数是n 个居民点到邮局的距离总和的最小值。

输入文件示例               输出文件示例

input.txt                  output.txt

5                          10

1 2

2 2

1 3

3 -2

3 3

代码如下:

  1. #include <iostream>
  2. #include <algorithm>//sort()函数头文件
  3. using namespace std;
  4. #define N 10000
  5. bool cmp(int a,int b){
  6. return a<b;
  7. }
  8. int main()
  9. {
  10. int n;cin>>n;
  11. int X=0, Y=0;//(X,Y)记录邮局位置
  12. int MinDis=0;
  13. int x[N],y[N];
  14. for(int i=0;i<n;i++){
  15. cin>>x[i]>>y[i];
  16. }
  17. //街区中任意2 点(x1,y1) 和(x2,y2) 之间的距离可以用数值|x1-x2|+|y1-y2| 度量。
  18. //所以可将x,y分开计算
  19. sort(x,x+n,cmp);//排序
  20. sort(y,y+n,cmp);//排序
  21. X=x[n/2];Y=y[n/2];
  22. //下图有解释,为何取[n/2],以及坐标数为奇/偶数此取值皆满足
  23. //邮局位置找法思想,两边之和大于第三边,x取值必须在以两点为一组,在其连线上
  24. for(int i=0;i<n;i++){
  25. int dis1=x[i]-X;int dis2=y[i]-Y;
  26. if(dis1<0) dis1=-1*dis1;//距离为正值,若作差为负数,则取相反数
  27. if(dis2<0) dis2=-1*dis2;//距离为正值,若作差为负数,则取相反数
  28. MinDis=MinDis+dis1+dis2;//求和
  29. }
  30. cout<<MinDis<<endl;
  31. return 0;
  32. }

 

三、集合划分问题

3.集合划分问题

问题描述:

  n 个元素的集合{1,2,., n }可以划分为若干个非空子集。例如,当n=4 时,集合{1,2, 3,4}可以划分为15 个不同的非空子集如下:

{{1},{2},{3},{4}},

{{1,2},{3},{4}},

{{1,3},{2},{4}},

{{1,4},{2},{3}},

{{2,3},{1},{4}},

{{2,4},{1},{3}},

{{3,4},{1},{2}},

{{1,2},{3,4}},

{{1,3},{2,4}},

{{1,4},{2,3}},

{{1,2,3},{4}},

{{1,2,4},{3}},

{{1,3,4},{2}},

{{2,3,4},{1}},

{{1,2,3,4}}

其中,集合{{1,2,3,4}} 由1 个子集组成;集合{{1,2},{3,4}},{{1,3},{2, 4}},{{1,4},{2,3}},{{1,2,3},{4}},{{1,2,4},{3}},{{1,3,4},{2}},{{2, 3,4},{1}} 由2 个子集组成;集合{{1,2},{3},{4}},{{1,3},{2},{4}},{{1,4}, {2},{3}},{{2,3},{1},{4}},{{2,4},{1},{3}},{{3,4},{1},{2}} 由3 个子集组成;集合{{1},{2},{3},{4}} 由4 个子集组成。

编程任务:

  给定正整数n 和m,计算出n 个元素的集合{1,2,., n }可以划分为多少个不同的由m 个非空子集组成的集合。

数据输入:

  由文件input.txt 提供输入数据。文件的第1 行是元素个数n 和非空子集数m。

结果输出:

  程序运行结束时,将计算出的不同的由m个非空子集组成的集合数输出到文件output.txt 中。

输入文件示例            输出文件示例

input.txt               output.txt

4    3                      6

 代码如下:

  1. #include <iostream>
  2. using namespace std;
  3. int num(int n, int m){
  4. if(n==m||m==1) return 1;
  5. else{return num(n-1,m-1)+num(n-1,m)*m;}
  6. }
  7. int main()
  8. {
  9. int n,m;cin>>n>>m;
  10. cout<<num(n,m)<<endl;
  11. return 0;
  12. }

 对{1,2,3}进行划分:

(1)、1个子集:{1,2,3}        即num(3,1)=1

(2)、2个子集:{1,2},{3}    {1,3},{2}     {2,3},{1}        即num(3,2)=3

(3)、3个子集:{1},{2},{3}        即num(3,3)=1

对{1,2,3,4}进行划分为3个子集:

(1),在对{1,2,3}划分为两个子集的结果中加入{4}: {1,2},{3},{4}    {1,3},{2},{4}     {2,3},{1},{4}        此个数为num(3,2)

(2),在对{1,2,3}划分为三个子集的结果中加入元素4:{1,4},{2},{3}        {1},{2,4},{3}        {1},{2},{3,4}        此个数为num(3,3)*3

综上所述:

num(4,3)=num(3,2)+num(3,3)*3

推广至num(n,m)为:        num(n,m)=num(n-1,m-1)+num(n-1,m)*m  

且当 n==m或者m==1时,num(n,m)=1

四、输油管道问题

4.输油管道问题

问题描述:

  某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有n 口油井的油田。从每口油井都要有一条输油管道沿最短路经(或南或北)与主管道相连。如果给定n 口油井的位置,即它们的x 坐标(东西向)和y 坐标(南北向),应如何确定主管道的最优位置, 即使各油井到主管道之间的输油管道长度总和最小的位置?证明可在线性时间内确定主管道的最优位置。

编程任务:

  给定n 口油井的位置,编程计算各油井到主管道之间的输油管道最小长度总和。

数据输入:

  由文件input.txt 提供输入数据。文件的第1 行是油井数n,1<=n10000。接下来n 行是油井的位置,每行2 个整数x 和y,-10000<=x,y<=10000 。

结果输出:

  程序运行结束时,将计算结果输出到文件output.txt 中。文件的第1 行中的数是油井到主管道之间的输油管道最小长度总和。

输入文件示例       输出文件示例

input.txt           output.txt

5                       6

1 2

2 2

1 3

3 -2

3 3

代码如下:

  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. #define N 10000
  5. bool cmp(int a,int b){
  6. return a<b;
  7. }
  8. int main()
  9. {
  10. int n;cin>>n;
  11. int X=0, Y=0;//(X,Y)记录邮局位置
  12. int MinDis=0;
  13. int x[N],y[N];
  14. for(int i=0;i<n;i++){
  15. cin>>x[i]>>y[i];
  16. }
  17. sort(x,x+n,cmp);
  18. sort(y,y+n,cmp);
  19. X=x[n/2];Y=y[n/2];//邮局位置找法思想,两边之和大于第三边
  20. //将坐标两两分组,距离两点最近距离肯定在其两点间连线上,取交集即可;
  21. for(int i=0;i<n;i++){
  22. int dis1=x[i]-X;int dis2=y[i]-Y;
  23. if(dis1<0) dis1=-1*dis1;
  24. if(dis2<0) dis2=-1*dis2;
  25. MinDis=MinDis+dis2;
  26. //只需要y坐标距离差的绝对值(与第二题不同,此题为东西走向管道,不需考虑X坐标)
  27. }
  28. cout<<MinDis<<endl;
  29. return 0;
  30. }

五、 整数因子分解问题

5.整数因子分解问题

问题描述:

 大于1 的正整数n 可以分解为:n=x1*x2*…*xm。

例如,当n=12 时,共有8 种不同的分解式:

12=12;

12=6*2;

12=4*3;

12=3*4;

12=3*2*2;

12=2*6;

12=2*3*2;

12=2*2*3 。

编程任务:

  对于给定的正整数n,编程计算n 共有多少种不同的分解式。

数据输入:

  由文件input.txt 给出输入数据。第一行有1 个正整数n (1≤n≤2000000000)。

结果输出:

将计算出的不同的分解式数输出到文件output.txt 。

输入文件示例          输出文件示例

input.txt            output.txt

 12                      8

代码如下:

  1. #include <iostream>
  2. using namespace std;
  3. int factor(int n){
  4. int sum=0;
  5. for(int i=n;i>1;i--){
  6. if(n%i==0){//i是n的因子
  7. int j=n/i;
  8. if(factor(j)==0) sum++;
  9. else{
  10. sum=sum+factor(j);
  11. }
  12. }
  13. }
  14. return sum;
  15. }
  16. int main()
  17. {
  18. int n;cin>>n;
  19. cout<<factor(n)<<endl;
  20. return 0;
  21. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/716335
推荐阅读
相关标签
  

闽ICP备14008679号