C&C++实现算法习题第三部分—贪心算法(一)

6 篇文章 0 订阅

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

一. 活动安排问题

问题描述

设有n个活动的集合E= {1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si<fi.如果选择了活动i,则它在半开时间区间[si,fi)内占用资源。若区间[si,fi)与区间[sj,fj)不相交,则称活动i与活动j是相容的。也就是说,当si≥fj或sj≥fi时,活动i与活动j相容。活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合。.

实现代码
#include <iostream>
#include <malloc.h>

using namespace std;

void greedySelector(int n, int s[], int f[], int a[]);
int main()
{
    int s[] = {1,3,0,5,3,5,6,8,8,2,12};
    int f[] = {4,5,6,7,8,9,10,11,12,13,14};
    int n = 11;
    int *a;
    a = (int*)malloc(sizeof(int)*n);        //生成数组存储活动是否被安排
    for (int i = 0; i < n; i++){
        a[i] = 0;                           //将初始值都设置为0,默认不安排
    }

    greedySelector(n, s, f, a);
    return 0;
}

void greedySelector(int n, int s[], int f[], int a[])
{
    a[0] = 1;
    cout<<"第1个活动被安排"<<endl;
    int count = 1;    //用来记录被安排的活动的个数
    int j = 0;
    for (int i = 1; i < n; i++){    //从第二个开始遍历
        if (s[i] > f[j]){
            a[i] = 1;               //将该活动的标志设置为1
            j = i;                  //将该活动的标号赋给j,下一次比较用该活动
            count++;                //安排活动的数量加1
            cout<<"第"<<i+1<<"个活动被安排"<<endl;
        }
    }
    cout<<"总计有"<<count<<"个活动被安排"<<endl;
}

运行结果

图1
图2

二. 最优装载问题

问题描述

有一批集装箱要装上一艘载重量为c的轮船.其中集装箱i的重量为wi。最优装载问题要求在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。

实现代码
#include <iostream>

using namespace std;
//冒泡排序
void Sort(int *weight, int n){
     for (int i=n-1;i>0;i--)  {
        for(int j=0;j<i;j++){

            if(weight[j]>weight[j+1]){
                int temp=weight[j];
                weight[j]=weight[j+1];
                weight[j+1]=temp;
            }
        }
    }
}
//装载
void Loading(int *weight, int *judge, int c, int n){
    judge[0] = 1;   //经过排序后,将重量最轻的装载
    c -= weight[0];     //剩余可装载的重量是总重量减去第一个以后的重量
    int mainWeight = weight[0];
    for (int i = 1; i < n; i++){
        if (c-weight[i] >= 0){
            mainWeight += weight[i];
            judge[i] = 1;
            c -= weight[i];
        }
    }
    cout<<"装载到轮船上的有"<<endl;
    for (int j = 0; j < n; j++){
        if(judge[j] == 1){
            cout<<weight[j]<<"   ";
        }
    }
    cout<<endl;
    cout<<"总重量"<<mainWeight<<endl;

}

int main()
{
    int c = 100;    //轮船载重量
    int weight[6] = {100, 20, 50, 10, 11, 5};   //6个集装箱的重量
    Sort(weight,6);
    int judge[6] = {0};     //对是否装载进行判断,默认初始值为0
    Loading(weight, judge, c, 6);
    return 0;
}

运行结果

图3
图4

三. 会场安排问题

问题描述

假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。设计一个有效的贪心算法进行安排。

实现代码
#include <iostream>
#define MAXSIZE 100
#include<stdio.h>

using namespace std;

struct active{
    int sTime;
    int eTime;
};
void Bubblesort(struct active sa[],int sum){
     for (int i=sum-1;i>0;i--)  {
        for(int j=0;j<i;j++){

            if(sa[j].eTime>sa[j+1].eTime){
                struct active temp=sa[j];
                sa[j]=sa[j+1];
                sa[j+1]=temp;
            }
        }
    }
}

void greedy(struct active sa[],int sum)
{
    int i = 0,j = 0,k,flag = 0;

    int allTime[MAXSIZE] = {10000},degree,minTime = 0;
    Bubblesort(sa,sum);             //按结束时间进行排序
    degree = 1;                     //所需要的会场个数
    allTime[0] = sa[0].eTime;
    //第一个会场花费的时间默认是第一个活动的结束是啊金
    for(i = 1;i < sum; i++){
        for(k = 0;k <= j; k++){
            minTime = allTime[0];       //遍历找到结束时间最早的会场
            if(allTime[k] < minTime){
                minTime = allTime[k];
                flag = k;               //记录下当前的索引
            }
        }
        if(sa[i].sTime < minTime){
            degree++;                   //重新开辟一个会场
            allTime[j+1] += sa[i].eTime;//新会场的结束时间为当前会议的结束时间
            j++;
        } else {
            allTime[flag] += sa[i].eTime;//给最早结束的时间加上当前的
        }
    }
    cout<<"最少会场数为: "<<degree;
}

int main()
{
    int m,n,sum,i;
    struct active sa[MAXSIZE];
    cout<<"请输入待安排的活动数量"<<endl;
    cin>>sum;
    cout<<"请输入每个活动的开始时间和结束时间"<<endl;
    for(i = 0;i < sum; i++){
        cin>>m>>n;
        sa[i].sTime = m;
        sa[i].eTime = n;
    }
    greedy(sa,sum);

    return 0;
}

运行结果

图5

四. 磁带最优存储问题

问题描述

磁带最优存储问题要求确定n个程序在磁带上的一个存储次序,使平均读取时间达到最小。

实现代码
#include <stdio.h>
#include <stdlib.h>
#define SIZE 100
struct tap
{
    int a;     //程序长度
    int b;     //读取概率
}A[SIZE];

void  sort(float B[],int n);//进行排序的函数
float greedy(struct tap A[],int n);//进行贪心算法的函数

int main()
{
    int i ,n;
    printf("请输入程序个数:\n");
    scanf("%d",&n);
    printf("请输入程序长度和读取概率\n");
    for(i = 0;i < n;i++){
        scanf("%d",&A[i].a);
        scanf("%d",&A[i].b);
    }
    printf("平均读取时间最小为:%f",greedy(A,n));
    return 0;
}
void sort(float B[],int n)
{
    int i,j,temp;
    for(i = 0;i < n;i++)
    {
        for(j = i + 1;j < n;j++)
        {
            if(B[i] > B[j])
            {
                temp = B[i];
                B[i] = B[j];
                B[j] = temp;
            }
        }
    }
}
float greedy(struct tap A[],int n)
{
    float B[SIZE];      //用来保存p*l
    int i,sum =0;
    float time = 0;
    for(i = 0;i < n; i++)
    {
        B[i] = A[i]. b*A[i].a;    //计算每个程序所需的时间,即p*l乘积
        sum += A[i].b;            //对输入的概率求和
    }
    sort(B,n);                //按p*l由小到大排序

    for(i = 0;i < n; i++)
    {
       time += (n-i)*B[i];    /*5*B[0]+4*B[1]+3*B[2]+2*B[1]+B[0]*/
    }
    return time/sum;
}


运行结果

图6

参考文献 《计算机算法设计与分析(第四版)》 王晓东 编著

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值