第四周集训总结

本文详细介绍了贪心算法和分治算法的概念、基本思路以及应用示例。通过具体的题目分析,如导弹拦截、活动选择、纪念品分组等,展示了这两种算法在解决问题时的策略选择和效果。同时,文中还探讨了贪心策略的选择条件和分治算法的分解、解决和合并步骤,强调了局部最优解和全局最优解的关系。
摘要由CSDN通过智能技术生成

贪心算法

定义

在对问题求解时,总是做出在当前看来是最好的选择。不从整体最优上加以考虑,所做出的仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。

基本思路

1.建立数学模型来描述问题。

2.把求解的问题分成若干个子问题。

3.对每一子问题求解,得到子问题的局部最优解。

4.把子问题的解局部最优解合成原来解问题的一个解。

适用的问题

贪心策略适用的前提是:局部最优策略能导致产生全局最优解。实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。

贪心策略的选择

因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。

分治算法

定义

分治算法核心是:分而治之,就是将原问题划分成n个规模较小,并且和原问题相似的子问题,递归的去解决这些问题,然后将结果合并,最后得到原问题的答案。

分治算法的递归实现中,每一层递归都包含了这样三个操作:

  1. 分解:将原问题分解成一系列子问题。
  2. 解决:递归地求解各个子问题,若子问题足够小,则直接求解。
  3. 合并:将子问题的结果合并成原问题。

分治算法原则如下:

  1. 原问题和子问题使用相同的计算模式
  2. 子问题之间相互独立,不会相互影响
  3. 当子问题足够小,可以直接求解出答案
    子问题解决后,还可以合并为原问题期望的结果,而且合并的时间复杂度要低于原问题直接解决的时间复杂度

(例)归并排序-分治算法

问题描述:

输入:待排序列r[n],待排区间[s,t]
输出:升序序列r[s]~r[t]

分析:

  1. 划分
  2. 求解子问题
  3. 合并

归并排序首先执行划分过程,直到子序列长度为1,再在回溯的过程中排序。在merge_()函数中,由于回溯回来的两个子序列已经有序,所以只需依次取出两者中最小值中的较小者即可。

#include <iostream>

using namespace std;

void Mergesort(int r[],int s,int t);
void merge_(int r[],int s,int m,int t);

int r[10010],r1[10010];

int main()
{
   
    int n,i;
    cin>>n;
    for(i=0;i<n;i++)
        cin>>r[i];
    Mergesort(r,0,n-1);
    for(i=0;i<n;i++)
        cout<<r[i]<<" ";
    cout<<endl;
    return 0;
}


void Mergesort(int r[],int s,int t)
{
   
    if(s == t)
        return ;
    else
    {
   
        int m = (s+t)/2;
        Mergesort(r,s,m);
        Mergesort(r,m+1,t);
        merge_(r,s,m,t);
        for(int i=s;i<=t;i++)
            r[i] = r1[i];
    }
}

void merge_(int r[],int s,int m,int t)
{
   
    int i=s,j=m+1,k=s;
    while(i<=m && j<=t)
    {
   
        if(r[i] <= r[j])
            r1[k++]=r[i++];
        else
            r1[k++]=r[j++];
    }
    while(i<=m)
        r1[k++]=r[i++];
    while(j<=t)
        r1[k++]=r[j++];
}

(二) 例题

导弹拦截

题目描述

某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统,但是这种拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭,由于该系统还在试用阶段。所以一套系统有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度不大于30000的正整数)。计算要拦截所有导弹最小需要配备多少套这种导弹拦截系统。

输入

n颗依次飞来的高度(1≤n≤1000)

输出

要拦截所有导弹最小配备的系统数k

样例输入

389 207 155 300 299 170 158 65

样例输出

2

提示

输入:导弹高度: 7 9 6 8 5

输出:导弹拦截系统K=2

输入:导弹高度: 4 3 2

输出:导弹拦截系统K=1

#include<bits/stdc++.h>
using namespace std;

int s[1005];
int l[1005];
int main()
{
   
	int n =1;
	memset(s,0,sizeof(s));
	memset(l,0,sizeof(s));
	while(cin >> s[n])
	{
   
		n++;
	}
	int k = 1;
	l[k] = s[1];
	int p = 0;
	for(int i = 2;i <n ;i++){
   
		p=0;
		for(int j = 1;j <=k;j++){
   
			if(l[j] >= s[i]){
   
				if(p==0) p = j;
				else if(l[j] < l[p]) p = j;
			}
		}
		if(p==0){
   
			k++;
			l[k] = s[i];
		}
		else{
   
			l[p] = s[i];
		}
	}
	cout << k << endl;
}

活动选择

题目描述

学校在最近几天有n个活动,这些活动都需要使用学校的大礼堂,在同一时间,礼堂只能被一个活动使。由于有些活动时间上有冲突,学校办公室人员只好让一些活动放弃使用礼堂而使用其他教室。

现在给出n个活动使用礼堂的起始时间bi和结束时间ei(bi < ei<=32767),请你帮助办公室人员安排一些活动来使用礼堂,要求安排的活动尽量多。

输入导弹依次飞来的高度(雷达给出的高度不大于30000的正整数)。计算要拦截所有导弹最小需要配备多少套这种导弹拦截系统。

输入

第一行一个整数n(n<=1000); 接下来的n行,每行两个整数,第一个bi,第二个是ei(bi < ei<=32767)

输出

输出最多能安排的活动个数

样例输入

11
3 5
1 4
12 14
8 12
0 6
8 11
6 10
5 7
3 8
5 9
2 13

样例输出

4

#include<bits/stdc++.h>
using namespace std;

const int MAXN
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值