天天看点

算法设计与分析——第四章贪心算法复习

文章目录

    • 4.1 贪心概述
    • 4.2 活动安排问题
    • 4.3 最优装载问题
    • 4.4 最优前缀码及哈夫曼算法
    • 4.5 多机调度问题
    • 4.6 最优分解问题

4.1 贪心概述

算法设计与分析——第四章贪心算法复习
算法设计与分析——第四章贪心算法复习
算法设计与分析——第四章贪心算法复习

4.2 活动安排问题

算法设计与分析——第四章贪心算法复习

按照 e [ ] e[] e[]从小到大将数组 e [ i ] 、 s [ i ] e[ i ]、s[ i ] e[i]、s[i] 进行排序, j j j 从 i + 1 i+1 i+1 到n开始遍历找 s [ j ] > e [ i ] s[j]>e[i] s[j]>e[i] 的活动,这个活动就可以安排在 e [ i ] e[ i ] e[i]的后面,此时让 j = i j=i j=i 更新最后一个活动,num++(num记录能安排的活动总数)

#include <iostream>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
//冒泡排序,按照e[]从小到大将数组排序
void buble(int a[],int b[],int n)
{
    int i,j;
    for(i=1; i<=n; i++)
        for(j=i; j<=n-i-1; j++)
        {
            if(a[j]<a[i])
            {
                int t1=a[i];
                a[i]=a[j];
                a[j]=t1;

                int t2=b[i];
                b[i]=b[j];
                b[j]=t2;
            }
        }
}
int group(int s[],int e[],int n)//返回可安排的总活动数
{
    int i=1;//取第一个
    int num=1;
    for(int j=i+1; j<=n; j++) //找e[i+1]>s[i]的活动数
    {
        if(s[j]>=e[i])
        {
            //printf("s[%d]=%d e[%d]=%d\n",i,i,s[i],e[i]);
            // printf("s[%d]=%d e[%d]=%d\n",j,j,s[j],e[j]);
            // printf("================================\n");
            num++;
            i=j;//找到了就将第i+1个活动赋成最后一个
        }
    }
    return num;
}


int main()
{
    int s[100],e[100];
    int n;
    printf("输入活动数n=");
    cin>>n;
    e[0]=n;
    for(int i=1; i<=n; i++)
    {
        cin>>s[i]>>e[i];
    }

    buble(e,s,n);
    // for(int i=1;i<=n;i++)
    //    printf("%d %d\n",s[i],e[i]);
    cout<<group(s,e,n);
}
/*
10
1 4
3 5
0 6
5 7
3 8
5 9
6 10
8 11
8 12
2 13
*/
           

4.3 最优装载问题

更多查阅参考文章

算法设计与分析——第四章贪心算法复习

输入:

物品i 1 2 3 4 5
重量wi 30 24 10 35 40

输出:

x[i],判断每个箱子是否能被装入。

算法设计与分析——第四章贪心算法复习
#include <iostream>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
//按照集装箱重量从小到大将集装箱的序号排序
void Sort(int w[],int t[],int n)
{
    int temp;
    for(int i=1;i<=n;i++)
        t[i]=i;//默认集装箱序号升序
    for(int i=1;i<=n;i++)//将轻的箱子序号前移
    {
        for(int j=1;j<=n;j++)
        {
            if(w[j+1]<w[j])
            {
                temp=t[j];
                t[j]=t[j+1];
                t[j+1]=temp;
            }
        }
    }
}
void Loading(int x[],int w[],int c,int n)
{
    int t[n];
    Sort(w,t,n);//得到t[],标注从小到大的箱子序号
    for(int i=1;i<=n;i++)
        x[i]=0;//初始化都不能装
    //i=1,w[t[i]]<c表示拿出小的箱子,判断他的重量是否小于c,小于则装入x[i]=1
    for(int i=1;i<=n&&w[t[i]]<=c;i++)
    {
        x[t[i]]=1;
        c=c-w[t[i]];//可装入的质量变小
    }
}
int main()
{
    int n,c;
    int w[100],x[100];
    cin>>n>>c;
    for(int i=1;i<=n;i++)
        cin>>w[i];
    Loading(x,w,c,n);
    for(int i=1;i<=n;i++)
        cout<<x[i]<<' ';
    return 0;
}
/*
5 100
30 24 10 35 40
*/
           

4.4 最优前缀码及哈夫曼算法

算法设计与分析——第四章贪心算法复习

4.5 多机调度问题

参考文章

某工厂有n个独立的作业,由m台相同的机器进行加工处理。作业i所需的加工时间为ti,任何作业在被处理时不能中断,也不能进行拆分处理。现厂长请你给他写一个程序:算出n个作业由m台机器加工处理的最短时间。

引入C++的vector知识点:

定义具有10个整型元素的向量(尖括号为元素类型名,它可以是任何合法的数据类型),不具有初值,其值不确定

vector<int>a(10);

//定义具有10个整型元素的向量,且给出的每个元素初值为1

vector<int>a(10,1);

按照作业时间将作业从小到大排序,每次将耗时长的作业分给当前耗时少的机器,这样就能达到最少的时间。

我们用t[i]记录第i个作业的消耗时间,machine[i]记录第i个机器当前耗时,machine_time记录当前的最小耗时,来更新index记录当前最小耗时的机器号,这样通过遍历就能更新找到最小的index以及machine_time。

#include<iostream>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
vector <int> t{2,14,4,16,6,5,3};//每个作业的的处理时间
int machine[100];//机器i的耗时
int mintime(int m)//m个机器
{
    sort(t.begin(),t.end());//从小到大排序
    int n=t.size();
    int machine_time;
    if(n<m)//机器的数量>作业数,时间为最长的作业时间
        return t[n-1];
    else
    {
        for(int i=n-1;i>=0;i--)//从耗时最大的作业开始分配
        {
            int index=0;//记录耗时最小的machine号
            machine_time=machine[index];//记录最小时间
            for(int j=1;j<m;j++)//找当前时间的最小machine
            {
                if(machine[j]<machine_time)
                {
                    index=j;
                    machine_time=machine[j];
                }
            }
            machine[index]+=t[i];
        }
        n=machine[0];//取最小时间
        for(int i=1;i<m;i++)
            n=n<machine[i]?machine[i]:n;
    }
    return n;
}

int main()
{
    int m;//机器的数量
    cin>>m;
    printf("最小时间:%d",mintime(m));
}
/*
输入:
3
输出:
17
*/

           

4.6 最优分解问题

设n是一个正整数,现在要求将n分解为若干个互不相同的自然数的和,且使这些自然数的乘积最大。

输入示例
  10 
输出示例
  30=2*3*5
输入示例
  20 
输出示例
  2*3*4*5*6=720
           

若a+b=n,则|a-b|越小,那么,a*b越大。

对于能分解为多个数的n来说,分解出的数字越多且越相近则乘积越大

例如:19

分解为2,3,4,5 (5)

由于是依次递增,所以剩余5不能再分解,这4个数字全部加1,还剩1,最后一位加1即可。

#include<iostream>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
int a[100];
int Break_up(int n)
{
    int n1=0,sum=0;
    a[2]=2;
    int i=2;//分解为2的连续数
    while(n-sum>=i)
    {
        sum+=i;//拆解掉的数的和
        a[i]=i;//将拆出来的数存到a[i];
        i++;
        n1++;//记录拆解的个数
    }
    int left=(n-sum)%n1;//未被整除的部分
    for(int j=i-1; j>=2; j--)
        a[j]+=(n-sum)/n1;//求出每个a[i]要加的数(整除的部分)

    for(int j=i-1; j>i-1-left; j--)//从最后一个向前加
        a[j]++;
    return n1;
}

int main()
{
    int n,n1,sum=1;
    cin>>n;
    n1=Break_up(n);
    for(int j=2; j<n1+2; j++)
    {
        sum*=a[j];
        (j==2)?cout<<a[j]:cout<<"*"<<a[j];
    }
    cout<<"="<<sum;

}
/*
输入:
8
输出:
3*5=15

输入:
19
输出:
3*4*5*7=420
*/

           

继续阅读