IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 训练营第四周 分治法 贪心法 -> 正文阅读

[数据结构与算法]训练营第四周 分治法 贪心法

本文章由网安三兄弟合作编写。


分治法

分治法顾名思义就是分而治之,将大问题划分成一些规模较小的子问题,从而各个击破。
使用分治法题目的两大特征:
①平衡子问题:子问题的规模大致相同,能把问题分成两个规模相等的子问题。
②独立子问题:子问题之间相互独立。这是区别于动态规划算法的基本特征,在动态规划算法中子问题是相互联系的。
分治法能大大优化算法的复杂度,一般情况下能把O(n)的复杂度优化到O(log2n).
分治法建立模型的解题步骤分为:分解,解决,合并三步。
代码模板(参考y总)

1.快速排序

void quick_sort(int q[],int l,int r){
    if(l>=r) return;
    int x=q[l],i=l-1,j=r+1;
    while(i<j){
        do i++;while(q[i]<x);
        do j--;while(q[j]>x);
        if(i<j) swap(q[i],q[j]);
    }
    quick_sort(q,l,j);
    quick_sort(q,j+1,r);
}

2.归并排序

void merge_sort(int a[],int l,int r){
    if(l>=r) return;
    int mid=l+r>>1;
    merge_sort(a,l,mid),merge_sort(a,mid+1,r);
    int k=0,i=1,j=mid+1;
    while(i<=mid&&j<=r){
        if(a[i]<=a[j]) tmp[k++]=a[i++];
        else tmp[k++]=a[j++];
    }
    while(j<=mid) tmp[k++]=a[i++];
    while(j<r) tmp[k++]=a[j++];
    for(i=1,j=0;i<=r;i++,j++) a[i]=tmp[j];
}

排序问题是竞赛中的常用功能,一般可直接使用stl中的sort函数,
sort(a+1,a+1+n);//从小到大对a[1]到a[n]排序。
下面给出两道简单例题:

快速排序

#include<iostream>
using namespace std;
const int N = 100001;
int q[N];
void quick_sort(int q[], int l, int r) {
	if (l >= r) return;
	int x = q[(l+r)/2], i = l - 1, j = r + 1;
	while (i < j) {
		do i++; while (q[i] < x);
		do j--; while (q[j] > x);
		if (i < j) swap(q[i], q[j]);
	}
	quick_sort(q, l, j);
	quick_sort(q, j + 1, r);
}
int main() {
    int n;
	scanf("%d",&n);
	for (int i = 0; i < n; i++) scanf("%d",&q[i]);
	quick_sort(q, 0, n - 1);
	for (int i = 0; i < n; i++) printf("%d ",q[i]);
	return 0;
}

归并排序

#include<iostream>
using namespace std;
const int N = 1000001;
int n;
int a[N], tmp[N];
void merge_sort(int a[], int l, int r) {
	if (l >= r) return;
	int mid = l + r >> 1;
	merge_sort(a, l, mid), merge_sort(a, mid + 1, r);
	int k = 0, i = l, j = mid + 1;
	while (i <= mid && j <= r) {
		if (a[i] <= a[j]) tmp[k++] = a[i++];
		else tmp[k++] = a[j++];
	}
	while (i <= mid) tmp[k++] = a[i++];
	while (j <= r) tmp[k++] = a[j++];
	for (i = l, j = 0; i <= r; i++, j++) a[i] = tmp[j];
}
int main() {
	scanf("%d", &n);
	for (int i = 0; i < n; i++) scanf("%d", &a[i]);
	merge_sort(a, 0, n - 1);
	for (int i = 0; i < n; i++) printf("%d ", a[i]);
	return 0;
}

参考练习题

hdu 1425,求前k大的数;
poj 2388,求中间数;


贪心算法

概述

贪心是最容易理解的算法思想,把整个问题分解成多个步骤,在每个步骤都选取当前步骤的最优方案,直到所有步骤结束。即每次都使用短视判断做出局部最优解的选择,循环计算局部最优解的操作,直至出现计算结束。

贪心算法是一种算法思想,这种通过反复计算局部最优解以得到全局最优解的思路,给人的感觉并不靠谱——因为局部最优解并不一定是全局最优解(例如局部的极大值并不一定等于全局的最大值),而事实也确实如此——并不是所有的问题都能通过贪心算法获得最优解。

下面介绍的是两个经典的贪心问题——Huffman编码、模拟退火。

Huffman编码

Huffman编码(哈夫曼编码)是贪心思想的典型应用。

Huffman编码是一种可变长编码,它是一种依据字符串中每个字符的出现概率构造出平均编码长度最短的编码方式。

例如,有a,b,c三个字符,其中a出现的次数最多,那么我们可以用单个二进制位表示a(例如表示为0),用相对较长的二进制位表示出现频率较低的字符b,c(例如可以表示为1011)。

Huffman算法符合贪心算法的“最优子结构性质”和“贪心选择性质”,是利用贪心思想构造二叉编码树的算法。

例题

输入一个字符串,分别用普通ASCII编码(每个字符8bit)和Huffman编码,输出编码后的长度,并输出压缩比。

输入样例

AAAAABCD

输出样例

64 13 4.9

import heapq
def ASCII(S): # 计算ASCII编码长度
    return 8 * len(S)
def Huffman(S):
    cnt = 1
    T = [i for i in S]
    T.sort(key=lambda x: ord(x))
    A = []
    heapq.heapify(A)
    for i in range(1,len(S)):	# 统计出现每个字符出现次数并送入堆
        if T[i] != T[i - 1]:
            heapq.heappush(A,cnt)
            cnt = 1
        else:
            cnt += 1
    if cnt: heapq.heappush(A,cnt)
    res = 0
    while len(A) > 1:
        x = heapq.heappop(A)
        y = heapq.heappop(A)
        heapq.heappush(A,x + y)
        res += x + y
    return res

S = input()
a = ASCII(S)
b = Huffman(S)
print(a,b,round(a / b,1))
为什么使用每个字符的出现次数,就能计算出Huffman编码的长度呢?

我们注意到,Huffman函数中,使用小顶堆作为存储每个字符出现次数的容器。每一次从堆中取出的两个元素x,y,便是这组数中的两个最小的数。在每一次循环中,我们将x,y相加后再次放入堆中,同时会讲x,y计入res中。借助Huffman树做理解,每个数都分别处于叶子的位置,x,y作为最小的值(代表着某字符出现的最小次数),存储的深度最深,被加的次数无疑应该是最多的(相比起将更大的树放在树的最深处,使用最小的两个值,计算的结果,也即是编码的长度也将将会更小)。


模拟退火

为了更好地理解模拟退火算法,我们可以先了解一下“爬山算法”。

爬山算法是一种完全基于贪心思想的算法。这个算法会在当期的接临近的解空间中选择一个最优解作为当前解,知道达到一个局部最优解。

爬山算法是一个“地道的”贪心算法,因此它往往也有着贪心所具有的缺陷——利用爬山算法所求得的局部最优解并不一定等于全局最优解(如将爬山算法运用于一个连续函数上,它所求出的最值可能只是局部的一个极值)。

而模拟退火算法,则是贪心思想与概率的结合,它通过对概率的巧妙运用,达到跳过局部最优解并最终找到全局最优解的目的。

模拟退火的步骤

  1. 设置一个初始的温度T
  2. 温度下降,状态转移。从当前温度按降温系数下降到下一个温度,在新的温度计算当前状态。
  3. 如果温度降到设定的温度下界,程序停止。

例题

函数 F ( x ) = 6 x 7 + 8 x 6 + 7 x 3 + 5 x 2 ? y x F(x) = 6x^7+8x^6+7x^3+5x^2-yx F(x)=6x7+8x6+7x3+5x2?yx??,其中x的范围是 0 ≤ x ≤ 100 0≤x≤100 0x100?。

输入y值,输出F(x)的最小值。

分析

因为F(x)是一个多项式函数,而多项式函数具有连续性,所以我们可以考虑通过贪心法求得最值。

但有一个问题会对传统的贪心法产生严重的影响——F(x)的图像具有多个峰,用——爬山法(传统的贪心法)计算出来的可能只是一个局部最大值,而非全局最大值。而能够以一定的概率跳过局部最优解从而找到全局最优解的模拟退火算法,则显现出了它在这类问题上独特的优势。

代码

import random
y = float(input())

def F(x):
    global y
    return 6 * x ** 7 + 8 * x ** 6 + 7 * x ** 3 + 5 * x ** 2 - y * x

def solve():
    T = 100	# 初始温度
    delta = 0.98	# 降温系数
    eps = 1e-8		# 终止温度
    flag = (1,-1)	# 正负号标识
    x = 50			# x,初始时取[0,100]的中点
    newx = 50		# 存储以一定概率接受的新x
    ans = F(x)		# 存最小值

    while T > eps:
        newx = x + flag[random.randint(0,1)] * T # 关键代码
        if newx >= 0 and newx <= 100:
            res = F(newx)
            if res < ans:
                ans = res
                x = newx
        T *= delta
    return ans

print(solve())
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-27 12:07:09  更:2021-08-27 12:08:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:34:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码