算法设计与分析-贪心算法

问题A: 贪心算法-汽车加油问题

题目描述

已知一辆汽车加满油之后可行驶n公里,旅途中有k(假设k<=20)个加油站(相邻两个加油站的距离小于等于n),出发之前汽车已经加满油。设计一个有效的贪心算法(贪心思想:加满油之后尽可能走过多个站点),指出应在旅途中的哪些加油站停靠加油,使沿途加油次数最少。

输入

第一行输入两个正整数,分别表示n和k
第二行输入k个正整数,分别表示相邻两个加油站之间的距离

输出

第一行输出最少的加油次数
第二行输出在哪些站点加油(1表示加油,0表示不加油,相邻两个数之间用一个空格隔开)

样例输入

 复制

70 8
10 20 30 40 50 10 60 60
样例输出

 复制

4
0 0 1 1 0 1 1 0
#include <stdio.h>
#include<stdlib.h>
 
int f(int dist[],int x[],int n,int k){
    int count=0;      //记录加油的次数
    int y=0;      //记录上次加油之后已经走过的路程
     
    for(int i=1; i<=k; i++){
        if(y+dist[i]>n){
            x[i-1] = 1;
            count++;
            y = dist[i];
        }else{
            y += dist[i];
        }
    }
     
    return count;
}
 
int main(void) {
    int i,n,k;      // n表示加满油之后最多可以行驶的距离,k表示沿图有k个加油站点 
    int dist[21]; //表示相邻两个站点之间的距离,0号单元不存储有效数据 
    int x[21];    //解向量,0号单元不存储有效数据,x[i]=0表示第i个加油站不加油,x[i]=1表示第i个加油站加油
 
    scanf("%d %d",&n,&k);
    for(i=1; i<=k; i++)scanf("%d",&dist[i]);
    for(i=1; i<=k; i++)x[i]=0; //初始化旅途中各个站点都不加油 
     
    printf("%d\n", f(dist,x,n,k));
        for(i=1; i<=k; i++)printf("%d ",x[i]);
     
    return 0;
}

问题B: 贪心算法-背包问题

题目描述

给定n(1<=x<=20)种不同的物品和一背包。物品i (1≤i≤n) 的重量是wi (wi 是大于 0的整数),其价值为vi(vi 是大于 0的整数),背包的容量为c (c 是大于 0的整数)。问应如何选择装入背包的物品(可以装入某个物品的一部分),使得装入背包中物品的总价值最大? 假设两个物品的价值重量之比相等则优先选择编号小的物品。
 

输入

第一行输入物品的个数以及背包的容量n和c
第二行输入每个物品的重量
第三行输入每个物品的价值

输出

输出n行,每行有两个数,第一个整数表示物品的编号(物品的编号按贪心选择的顺序输出),第二个实数表示对应物品的取舍情况(保留两位小数)

样例输入

 复制

4 50
20 30 10 5
100 120 60 2
样例输出

 复制

3 1.00
1 1.00
2 0.67
4 0.00
#include <stdio.h>
struct good {
    int w, v, id;  // w,v,id 分别表示物品的重量,价值和编号
    double x;      // x 在 0-1 之间取值,表示该物品需要放多少到背包中
    double ratio;  // 单位重量的价值
};

void f(struct good goods[], int n, int c) {
    int totalWeight = 0;
    double totalValue = 0;

    for (int i = 1; i <= n; i++) {
        if (totalWeight + goods[i].w <= c) {
            goods[i].x = 1.0;
            totalWeight += goods[i].w;
            totalValue += goods[i].v;
        } else {
            goods[i].x = (double)(c - totalWeight) / goods[i].w;
            totalWeight = c;
            totalValue += goods[i].x * goods[i].v;
            break;
        }
    }
}

void sort(struct good goods[], int n) {
    for (int i = 1; i <= n - 1; i++) {  // 冒泡排序(降序)
        for (int j = 1; j <= n - i; j++) {
            if (goods[j].ratio < goods[j + 1].ratio) {
                struct good temp;
                temp = goods[j];
                goods[j] = goods[j + 1];
                goods[j + 1] = temp;
            }
        }
    }
}

int main(void) {
    int i, n, c;
    struct good goods[21];  // 0 号单元不存储有效数据

    scanf("%d %d", &n, &c);
    for (i = 1; i <= n; i++) {
        scanf("%d", &goods[i].w);
    }
    for (i = 1; i <= n; i++) {
        scanf("%d", &goods[i].v);
    }
    for (i = 1; i <= n; i++) {
        goods[i].id = i;
        goods[i].x = 0;
        goods[i].ratio = 1.0 * goods[i].v / goods[i].w;
    }

    sort(goods, n);

    f(goods, n, c);

    for (i = 1; i <= n; i++) {
        printf("%d %.2f\n", goods[i].id, goods[i].x);
    }

    return 0;
}

问题C: 贪心算法-活动安排问题

题目描述

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

输入

第一行输入一个整数,表示有n个活动
第二行输入n个整数,分别表示每个活动的开始时间
第三行输入n个整数,分别表示每个活动的结束时间

输出

第1行输出最大相容活动的个数
第2-n+1行每行输出两个整数(两个整数之间用一个空格隔开),第一个整数表示活动编号,第二个整数表示该活动是否被选中(1:表示选择了对应的活动,0表示没有选择对应的活动)。

样例输入

 复制

11
1 3 0 5 3 5 6  8  8  2  12
4 5 6 7 8 9 10 11 12 13 14
样例输出

 复制

4
1 1
2 0
3 0
4 1
5 0
6 0
7 0
8 1
9 0
10 0
11 1
#include <stdio.h>

struct action {
    int s;    // 存储活动开始时间
    int f;    // 存储活动结束时间
    int id;   // 存储活动的编号
    int x;    // x=1表示选择了该活动,否则表示没有选择该活动
};

int fun(struct action a[], int n) {
    int i, sum = 0;
    int last_end_time = 0;  // 上一个选择的活动的结束时间

    // 从第一个活动开始进行选择
    for (i = 1; i <= n; i++) {
        if (a[i].s >= last_end_time) {
            // 如果当前活动的开始时间不早于上一个活动的结束时间,则选择当前活动
            a[i].x = 1;  // 标记选择了当前活动
            last_end_time = a[i].f;  // 更新上一个活动的结束时间
            sum++;  // 选择的活动数量加一
        } else {
            // 当前活动不符合选择条件,标记为未选择
            a[i].x = 0;
        }
    }
    return sum;
}

void sort(struct action a[], int n) {
    int i, j;
    // 按照活动的结束时间进行升序排序
    for (i = 1; i <= n - 1; i++) {
        for (j = 1; j <= n - i; j++) {
            if (a[j].f > a[j + 1].f) {
                struct action t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }
        }
    }
}

int main(void) {
    int i, n;
    struct action a[21];  // 0号单元不存储有效数据
    
    // 读取活动数量
    scanf("%d", &n);

    // 读取每个活动的开始时间
    for (i = 1; i <= n; i++) {
        scanf("%d", &a[i].s);
    }
    
    // 读取每个活动的结束时间
    for (i = 1; i <= n; i++) {
        scanf("%d", &a[i].f);
    }
    
    // 设置活动编号
    for (i = 1; i <= n; i++) {
        a[i].id = i;
    }

    // 对活动按结束时间排序
    sort(a, n);

    // 选择最大相容活动子集合,并获取活动数量
    int sum = fun(a, n);

    // 输出最大相容活动的个数
    printf("%d\n", sum);
    
    // 输出每个活动的编号和选择状态
    for (i = 1; i <= n; i++) {
        printf("%d %d\n", a[i].id, a[i].x);
    }

    return 0;
}

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值