【分治法】典型题目示例、含详细注释

简介: 【分治法】典型题目示例、含详细注释

  一、众数问题:

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

代码如下:

#include <iostream>
#include <algorithm>//sort()函数头文件 
using namespace std;
#define N 10000
bool cmp(int a,int b){
    return a<b;
}
int MaxNum=0;  //存储众数大小 
int MaxNumCount=0;  //存储众数个数 
int num[10000];
void split(int left,int right){
    if (left >=right) return;//越界跳出 
    int FirstLeft=left;//记录初始最左侧 
    int FirstRight=right;//记录初始最右侧 
    int mid=(left+right)/2;
    for(;left<mid &&num[left]!=num[mid];left++);//找到中位数的左临界 
    for(;right>mid&&num[right]!=num[mid];right--);//找到中位数的右临界 
    if(MaxNumCount<right-left+1){MaxNum=num[mid];MaxNumCount=right-left+1;} 
  //若此中位数个数大于众数个数,则更新 
  //若中位数左临界左边数字个数小于众数个数,则不需要执行下述操作;中位数右临界数字亦然 
    if(left-FirstLeft>MaxNumCount )split(FirstLeft,left-1);  
    if(FirstRight-right>MaxNumCount)split(right+1,FirstRight);
}
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++){
        cin>>num[i];
    }
    sort(num,num+n,cmp);//将数组从小到大排序
    int left0=0;int right0=n-1;
    split(left0,right0);
    cout<<MaxNum<<endl;
    cout<<MaxNumCount<<endl;
    return 0;
}

image.gif

二、邮局选址问题

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

代码如下:

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

image.gif

image.gif编辑

三、集合划分问题

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

代码如下:

#include <iostream>
using namespace std;
int num(int n, int m){
    if(n==m||m==1) return 1;
    else{return num(n-1,m-1)+num(n-1,m)*m;}
}
int main()
{
    int n,m;cin>>n>>m;
    cout<<num(n,m)<<endl;
    return 0;
}

image.gif

对{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

代码如下:

#include <iostream>
#include <algorithm>
using namespace std;
#define N 10000
bool cmp(int a,int b){
    return a<b;
}
int main()
{
    int n;cin>>n;
    int X=0, Y=0;//(X,Y)记录邮局位置
    int MinDis=0;
    int x[N],y[N];
    for(int i=0;i<n;i++){
        cin>>x[i]>>y[i];
    }
    sort(x,x+n,cmp);
    sort(y,y+n,cmp);
    X=x[n/2];Y=y[n/2];//邮局位置找法思想,两边之和大于第三边
    //将坐标两两分组,距离两点最近距离肯定在其两点间连线上,取交集即可;
    for(int i=0;i<n;i++){
        int dis1=x[i]-X;int dis2=y[i]-Y;
        if(dis1<0) dis1=-1*dis1;
        if(dis2<0) dis2=-1*dis2;
        MinDis=MinDis+dis2;
    //只需要y坐标距离差的绝对值(与第二题不同,此题为东西走向管道,不需考虑X坐标) 
    }
    cout<<MinDis<<endl;
    return 0;
}

image.gif

五、 整数因子分解问题

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

代码如下:

#include <iostream>
using namespace std;
int factor(int n){
    int sum=0;
    for(int i=n;i>1;i--){
        if(n%i==0){//i是n的因子 
            int j=n/i;
            if(factor(j)==0) sum++;
            else{
                sum=sum+factor(j);
            }
        }
    }
    return sum;
}
int main()
{
    int n;cin>>n;
    cout<<factor(n)<<endl;
    return 0;
}

image.gif


目录
相关文章
|
3月前
|
人工智能 监控 算法
AI(大模型)在公安案件侦办中的应用场景
本方案以AI赋能公安“案件侦办系统”,推出5款实战产品:AI笔录分析、证据链闭环验证、语义化知识库、多模态现场复现、全流程智能督办。聚焦提效、防错、赋能、合规,实现从“填表工具”到“实战中枢”的跃升。(239字)
741 2
|
4月前
|
存储 供应链 API
1688店铺详情API使用指南
1688店铺详情API是阿里巴巴开放平台核心接口,支持通过店铺ID获取商家基本信息、资质、等级及主营类目等数据,适用于电商分析、供应链对接等场景。本文详解接口参数、Python调用示例及注意事项,助开发者高效集成与应用。
|
4月前
|
人工智能 JSON 移动开发
AI 试衣服从“娱乐玩具”到真正可商用的能力进化
玩美移动AI Clothes技术专攻商业级虚拟试衣,突破通用大模型局限,实现服装结构精准还原、多体型真实适配、只换衣不换人。支持电商、APP快速集成,推动AI试衣从娱乐走向高转化零售应用。
771 0
|
数据采集 人工智能 自动驾驶
《突破AI数据标注高成本枷锁,势在必行!》
在人工智能快速发展的背景下,数据标注作为AI模型训练的基础,其高成本问题成为制约行业发展的关键因素。主要体现在人力、时间和管理成本上,尤其是在复杂领域和大规模数据处理中。为解决这一难题,行业探索了多种创新方案:技术层面,自动化标注工具与半监督学习技术显著提升效率;商业模式上,分布式众包和专业平台降低运营成本;人才培养方面,校企合作与激励机制优化标注质量。尽管仍存挑战,但通过多方协同,有望推动AI数据标注行业的高效发展,助力AI技术广泛应用。
572 9
|
JSON API 数据格式
App Inventor 2 天气预报App开发 - 第三方API接入的通用方法
通过调用第三方天气api,填入必要的参数,通过Web客户端请求url。返回json格式的数据结果,使用AppInventor2解析json结果,显示到App上即可。
649 5
|
前端开发 Java 应用服务中间件
Tomcat8中URI不支持{}|等特殊字符解决方案
Tomcat8中URI不支持{}|等特殊字符解决方案
783 0
|
资源调度 JavaScript 前端开发
CentOS 7.2 下安装配置Node.js和Yarn
centos下node.js的安装配置管理,npm以及yarn包管理工具的安装。
7193 0
|
前端开发 Java
SpringBoot的Web开发支持【超详细【一篇搞定】果断收藏系列】下
SpringBoot的Web开发支持【超详细【一篇搞定】果断收藏系列】
SpringBoot的Web开发支持【超详细【一篇搞定】果断收藏系列】下
|
存储 人工智能 数据中心
阿里云基础设施网络亮相SIGCOMM22 - 可预期网络取得重大突破
阿里云基础设施网络亮相SIGCOMM22 - 可预期网络取得重大突破
阿里云基础设施网络亮相SIGCOMM22 - 可预期网络取得重大突破
官宣!支付宝小程序的 23 个入口大盘点
近日,支付宝小程序场景值文档发布。场景值用于描述用户进入小程序的路径,也就是说,场景值即代表了的小程序入口 。
4413 12
官宣!支付宝小程序的 23 个入口大盘点