算法学习之贪心

1. 部分背包问题

题目来自洛谷,原题链接:https://www.luogu.com.cn/problem/P2240

题目描述

阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N(N≤100) 堆金币,第 i 堆金币的总重量

和总价值分别是 mi,vi(1≤mi,vi≤100)。阿里巴巴有一个承重量为 (T≤1000) 的背包,但并不一

定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。所有金币都可以随意分

割,分割完的金币重量价值比(也就是单位价格)不变。请问阿里巴巴最多可以拿走多少价

值的金币?

输入格式

第一行两个整数 N,TN,T。

接下来 N 行,每行两个整数 mi,vi 。

输出格式

一个实数表示答案,输出两位小数

输入输出样例

输入

4 50
10 60
20 100
30 120
15 45

输出

240.00

题目分析

先按照价值比对金币堆排序,优先放入价值比大的金币堆。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

/**
 * @Description
 * @Author:PrinceHan
 * @CreateTime:2022/3/19 20:08
 */
public class Main {
    static class Coin {
        int m;
        int v;
        double v_m;

        Coin(int m, int v) {
            this.m = m;
            this.v = v;
            this.v_m = (double) v / (double) m;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArrayList<Coin> coins = new ArrayList<>();
        int n = scanner.nextInt();
        int t = scanner.nextInt();
        double w = 0;
        for (int i = 0; i < n; i++) {
            int m = scanner.nextInt();
            int v = scanner.nextInt();
            coins.add(new Coin(m, v));
        }
        Collections.sort(coins, new Comparator<Coin>() {
            @Override
            public int compare(Coin o1, Coin o2) {
                if (o1.v_m == o2.v_m) return 0;
                else return o1.v_m > o2.v_m ? -1 : 1;
            }
        });
        for (int i = 0; i < n; i++) {
            if (t > coins.get(i).m) {
                w += coins.get(i).v;
                t -= coins.get(i).m;
            } else if (0 < t && t < coins.get(i).m) {
                w += t * coins.get(i).v_m;
                t = 0;
            } else break;
        }
        System.out.printf("%.2f", w);
    }
}

2. 排队接水

题目来自洛谷,原题链接:https://www.luogu.com.cn/problem/P1223

题目描述

有 n 个人在一个水龙头前排队接水,假如每个人接水的时间为 Ti,请编程找出这 n 个人排

队的一种顺序,使得 n 个人的平均等待时间最小。

输入格式

第一行为一个整数 n。

第二行 n 个整数,第 i个整数 Ti,表示第 i 个人的等待时间 Ti 。

输出格式

输出文件有两行,第一行为一种平均时间最短的排队顺序;第二行为这种排列方案下的平均

等待时间(输出结果精确到小数点后两位)。

输入输出样例

输入

10 
56 12 1 99 1000 234 33 55 99 812

输出

3 2 7 8 1 4 9 6 10 5
291.90

代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

/**
 * @Description
 * @Author:PrinceHan
 * @CreateTime:2022/3/19 19:47
 */
public class Main {
    static class Water {
        int water;
        int id;
        Water(int water, int id) {
            this.water = water;
            this.id = id;
        }
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArrayList<Water> waters = new ArrayList<>();
        int n = scanner.nextInt();
        double time = 0L;
        for (int i = 1; i <= n; i++) {
            int water = scanner.nextInt();
            waters.add(new Water(water, i));
        }
        Collections.sort(waters, new Comparator<Water>() {
            @Override
            public int compare(Water o1, Water o2) {
                return o1.water - o2.water;
            }
        });
        int len = waters.size();
        for (int i = 0; i < len; i++) {
            System.out.printf("%d ", waters.get(i).id);
            time += waters.get(i).water * (len - i - 1);
        }
        System.out.println();
        System.out.printf("%.2f", time / n);
    }
}

1872 · 连接棒材的最低费用

LintCode原题链接:1872 · 连接棒材的最低费用

题目分析

类似于哈夫曼树,每次合并两个最小的棒材,将合并的代价压入优先队列中,再加上合并的代价。优先队列默认按照升序排列,本质上是一个小根堆。

源码

public class Solution {
    /**
     * @param sticks: the length of sticks
     * @return: Minimum Cost to Connect Sticks
     */
    public int MinimumCost(List<Integer> sticks) {
        // write your code here
        if (sticks == null || sticks.size() == 0) return 0;
        int res = 0;
        PriorityQueue<Integer> q = new PriorityQueue<>(sticks);
        while (q.size() > 1) {
            int v = q.poll() + q.poll();
            res += v;
            q.add(v);
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值