算法期末备考一(贪心算法)

 贪心是局部最优一定整体最优。动规是局部最优整体不一定最优

目录

例题一(背包问题)

例题二(活动安排问题)

例题三(最优装载问题)

例题四(多机调度问题)

例题五(采集果子)

例题六(合并果子)

例题七(纪念品分组)

例题八(混合牛奶)

例题九(分发糖果)


例题一(背包问题)

【题目描述】

现在有很多物品(物品数量少于100个,它们是可以分割的),已知每个物品的单位重量的价值v和重量w(1<=v,w<=10);如果给你一个背包它能容纳的重量为m(10<=m<=20),你所要做的就是把物品装到背包里,使背包里的物品的价值总和最大。

【输入说明】

每组测试数据的第一行有两个正整数s,m(1<=s<=10);s表示有s个物品。接下来的s行每行有两个正整数v,w。

【输出说明】

输出每组测试数据中背包内的物品的价值和

【输入样例】

3 15

5 10

2 8

3 9

【输出样例】

65

代码:

#include
#include 

 struct Goods{
	int v,w;
}g[100];

int main(){
	int s,m;
	
	scanf("%d%d",&s,&m);//s个背包,承重m 
	for(int i=0 ;i=m)
		{
			ans +=m*g[i].v;
			m = 0;
			break;	
		}
		else{
			ans += g[i].v*g[i].w;//单价*重量 
			m = m-g[i].w;//表示剩余背包的重量 
		}
	}
	printf("%d\n",ans);
	
}

例题二(活动安排问题)

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

贪心策略:

就是按照每个任务的结束时间进行排序,然后每次取符合条件的最早结束的任务就可以了。

代码:

#include 
#define N 15

void sort(int S[],int F[],int n);
void arrange(int S[],int F[],int n);
int A[N]={0}; // 用来存储结果
int t[N]={0}; // 用来存储下标

void sort(int S[],int F[],int n){
    int i,j;
    //对结束时间进行排序
    for(j=1;j<=n;j++) { //有点类似冒泡排序
        for(i=1;iF[t[i+1]]){
                int temp = t[i];
                t[i] = t[i+1];
                t[i+1] = temp;
            }
        }
    }
}

void arrange(int S[],int F[],int n){
    int i,j=1;
    int a,b;
    A[t[1]] = 1;      //t[1]是结束时间最早的,会被选择
    a = t[j];         //a的作用是暂存,t数组中存放的是排序后的下标
    for(i=2;i<=n;i++){
        //如果结束时间大于第t[i]个的开始时间
        if(F[a]>S[t[i]]){
            A[t[i]] = 0;
        }else{
            A[t[i]] = 1;
            a = t[i];  //这里如果是t[j],那么赋值后t数组会变乱,因此用a暂存
        }
    }
}

int main(void){
    int S[N]={0},F[N]={0};
    int n,i;
	printf("请输入活动的个数:");
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        t[i] = i;     //t[i]初始化,没排序之前
        printf("请输入第%d个活动的开始时间和结束时间:",i);
        scanf("%d %d",&S[i],&F[i]);
    }

    sort(S,F,n);
    arrange(S,F,n);

    for(i=1;i<=n;i++) {
        if(A[i]==1) printf("%d ",i); //输出可以使用资源的活动
    }
    // printf("\n");

    // for(i=1;i<=n;i++){
    //     printf("%d ",t[i]);      //排序后的结果
    // }
    // printf("\n");
    return 0;
}

例题三(最优装载问题)

问题描述:

有n个物体,第i个物体的重量为wi(wi为正整数),选择尽量多的物体,使得总重量不超过C。

贪心策略:

每次选择重量最小的物品装入即可,先对物品按照重量从小到大进行排序,然后依次装入即可。

代码:

#include     
#define a 1005
int n,C;	//n个物体,最大载重量为C 
int we[a];	//第i个物体的重量
int main(){
	int i;
	int num=0;
	int sum=0;
	printf("请分别输入物体的数量和装载总重量:");
	scanf("%d %d",&n,&C);
	for(i=0;i we[k+1]) {
				int temp = we[k];
				we[k] = we[k + 1];
				we[k+1] = temp;
			}
		}
	}
	for(i=0;i

例题四(多机调度问题)

【问题描述】:

        要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。约定,每个作业均可在任何一台机器上加工处理,但未完工前不允许中断处理。作业不能拆分成更小的子作业。

【算法描述】:

        采用最长处理时间作业优先的贪心选择策略可以设计出解多
机调度问题的较好的近似算法。按此策略:
当n<=m时,只要将机器i的[0, ti]时间区间分配给作业i即可,算法只需要O(1)时间。
当n>m时,首先将n个作业依其所需的处理时间从大到小排序。然后依此顺序将
作业分配给空闲的处理机。算法所需的计算时间为O(nlogn)。

#include
#define N 8 //作业数
#define M 5 //机器数 
int s[M] = {0,0,0};//每台机器当前已分配的作业总耗时,这里也要做手动输入,根据题目来

//求出目前处理作业的时间和 最小的机器号
int min(int m){
    int min = 0;
    int i;
    for(i=1;i s[i]){
           min = i;
        }
    }
    return min; 
}
//求最终结果(最长处理时间)
int max(int s[],int num){
    int max = s[0];
    int i;
    for(i=1;i= N){
         maxtime = setwork1(time,N);
    }else{
         maxtime = setwork2(time,N); 
    } 
    printf("最多耗费时间%d。",maxtime);
}

例题五(采集果子)

一道力扣原题,题目链接:lcp 55采集果子

贪心策略:每次采最多的果子就好了,如果够了就不用采。

int getMinimumTime(int* time, int timeSize, int** fruits, int fruitsSize, int* fruitsColSize, int limit){
    int maxTime = 0; // 存放结果
    for(int i = 0; i < fruitsSize; i++){ // 遍历每次需要采集的果子数组
        // 统计多少次能够采集完成当前的果子
        int temp = fruits[i][1]/limit + (fruits[i][1]%limit == 0?0:1);
        // 用次数乘每次采集的时间,更新结果
        maxTime += temp * time[ fruits[i][0]];
    }
    return maxTime;
}

例题六(合并果子)

洛谷原题,题目链接:1090合并果子

贪心策略:每次都选最小的两个堆合并

#include
#include
#define INT_MAX 2147483647
int n,a[11000],ans=0; // 数组存的是每一堆果子的重量
bool vis[11000]={0};
void hebing(){
    int min1=INT_MAX,min2=INT_MAX; // 定义两堆最小的果子
    int t1,t2;
    for (int j=1;j<=n;++j) // 遍历果子,找到第一个最小的
        if ((!vis[j])&&(a[j]

例题七(纪念品分组)

洛谷原题,题目链接:1094纪念品分组

贪心策略:先排序,从两边往中间遍历,能两个分一组就两个分一组,不能就一个分一组

#include 
int p[30001]; // 存放物品
// 按下标交换
void swap(int x, int y) {
    int temp = p[x];
    p[x] = p[y];
    p[y] = temp;
}
int p1(int ks, int js) {
    int max = p[ks];
    int i = ks;
    int j = js + 1;
    while (1) {
        while (p[++i] > max && i < js);
        while (p[--j] < max);
        if (i >= j) break;
        swap(i, j);
    }
    swap(ks, j);
    return j;
}
// 快排
void qSort(int ks, int js) {
    int r;
    if (ks < js) {
        r = p1(ks, js);
        qSort(ks, r - 1);
        qSort(r + 1, js);
    }
}
int main() {
    int n, w, i, j, sum = 0;
    scanf("%d%d", &w, &n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &p[i]);
        if (w - p[i] < 5) { // 根据条件(5≤Pi≤w)做时间优化了, 就是如果太大直接在这里单个分为一组了
            i--;
            n--;
            sum++;
        }
    }
    qSort(0, n - 1); //排序
    for (int i = 0; i < n; i++) {
        if (p[i] + p[n-1]>w && i != n-1) sum++;
        else sum++, n--;
    }
    printf("%d",sum);
    return 0;
}

例题八(混合牛奶)

洛谷原题,题目链接:1208混合牛奶

#include

struct node{ // 结构体存的牛奶信息,方便排序
    int a; // 单价
    int b; // 总量
}q[5000];

int main() {
    int n, weight, ans=0;
    scanf("%d %d", &weight, &n); // 输入农民个数n和牛奶总量w
    for (int i = 0;i < n; i++) { // 输入农民的牛奶单价和他能卖出的量
        scanf("%d %d", &q[i].a, &q[i].b);
    }
    // 注意这里j是从0开始的,很像但不是冒泡,当然也可以用冒泡来写,都一样
    for (int i = 0; i < n; i++) { // 按照牛奶单价从小到大排序
        for (int j = 0; j < n; j++) {
            if (q[i].a < q[j].a) {
                int temp1 = q[i].a;
                int temp2 = q[i].b;
                q[i].a = q[j].a;
                q[j].a = temp1;
                q[i].b = q[j].b;
                q[j].b = temp2;
            }
        }
    }
	//for (int i = 0; i < n; i++)
	//	printf("%d ",q[i].a);
    while (weight) {
        for (int i = 0; i < n; i++) { // 依次选择价值小的放入就好了
            if (weight - q[i].b >=0 ) {
                weight -= q[i].b;
                ans += q[i].a * q[i].b;
            } else {
                ans += q[i].a * weight;
                weight=0;
                break;
            }
        }
        break;
    }
    printf("%d",ans);
    return 0;
}

例题九(分发糖果)

力扣原题,题目链接:135. 分发糖果

#define max(a, b) (((a) > (b)) ? (a) : (b))

int *initCandyArr(int size) {
    int *candyArr = (int*)malloc(sizeof(int) * size);
    int i;
    for(i = 0; i < size; ++i)
        candyArr[i] = 1;

    return candyArr;
}

int candy(int* ratings, int ratingsSize){
    // 初始化数组,每个小孩开始至少有一颗糖
    int *candyArr = initCandyArr(ratingsSize);

    int i;
    // 先判断右边是否比左边评分高。若是,右边孩子的糖果为左边孩子+1(candyArr[i] = candyArr[i - 1] + 1)
    for(i = 1; i < ratingsSize; ++i) {
        if(ratings[i] > ratings[i - 1])
            candyArr[i] = candyArr[i - 1] + 1;
    }

    // 再判断左边评分是否比右边高。
    // 若是,左边孩子糖果为右边孩子糖果+1/自己所持糖果最大值。(若糖果已经比右孩子+1多,则不需要更多糖果)
    // 举例:ratings为[1, 2, 3, 1]。此时评分为3的孩子在判断右边比左边大后为3,虽然它比最末尾的1(ratings[3])大,但是candyArr[3]为1。所以不必更新candyArr[2]
    for(i = ratingsSize - 2; i >= 0; --i) {
        if(ratings[i] > ratings[i + 1])
            candyArr[i] = max(candyArr[i], candyArr[i + 1] + 1);
    }

    // 求出糖果之和
    int result = 0;
    for(i = 0; i < ratingsSize; ++i) {
        result += candyArr[i];
    }
    return result;
}

例题十(碰撞问题)

【问题描述】

给定一个整数数组,表示在同一行的行星。
每一个元素,其绝对值表示行星的大小正负表示行星的移动方向
正表示向右移动,负表示向左移动每一颗行星以相同的速度移动。
碰撞规则∶
1、两个行星碰撞,较小的行星会爆炸。

2、如果大小相同,则两颗都会爆炸。
3、两颗移动方向相同的行星,永远不会发生碰撞。

#include 
#include 
#include 
int* collision(int *data, int dataSize, int* retSize){
    int n = 0;
    while(1){
        int pre = 0;
        int next = 1;

        while(next < dataSize){
            if(data[pre] * data[next] <0 ){//方向相反

                if(data[pre] <0 ){
                    pre = next;
                    next ++;
                    continue;
                }
                if(data[pre]>abs(data[next])){
                    data[next] = 0;
                    n++;
                }else if(data[pre]=dataSize){
            break;
        }
    }

    *retSize = dataSize - n;
    int i,k;
    int *retArray = (int*)malloc(*retSize * sizeof(int));
    for(i=0,k=0; i

例题十一(种花问题)

【问题描述】

一个很长的花坛,
一部分地已经种植了花,另一部分却没有。花不能种植在相邻的地块上
否则它们会争夺水源,两者都会死去。
给你一个整数数组表示花坛
由若干0和1组成
0表示没种植花,1表示种植了花。
给定一个数n
能不能种下n朵花?

#include 
#include 

bool canPLaceFlowers(int *data, int dataSize, int n){
  int i;

  if(n == 0){
    return true;
  }
  int count = 0;
  while(i0 && data[i-1] ==1){
        i+=1;
    }else if(i+1

超:

你可能感兴趣的:(贪心算法,算法,动态规划)