贪心类问题

排队打水

在这里插入图片描述

题解:

t 1 , t 2 , t 3 , . . . , t n − 1 , t n t_1,t_2,t_3, ...,t_{n-1},t_n t1,t2,t3,...,tn1,tn
等待时间计算的公式为: t 1 ∗ ( n − 1 ) + t 2 ∗ ( n − 2 ) + . . . + t n − 1 ∗ 1 t_1*(n-1)+t_2*(n-2)+...+t_{n-1}*1 t1(n1)+t2(n2)+...+tn11
t 1 , t 2 , t 3 , . . . , t n − 1 , t n t_1,t_2,t_3, ...,t_{n-1},t_n t1,t2,t3,...,tn1,tn为单调递增数列时,等待时间最小。
证明:
利用反证法,设排队顺序中存在 t i > t i + 1 t_i>t_{i+1} ti>ti+1
那么花在排在第 i i i个人上的等待时间为 t i ∗ ( n − i − 1 ) t_i*(n-i-1) ti(ni1)
花在排在第 i + 1 i+1 i+1个人上的等待时间为 t i + 1 ∗ ( n − i − 2 ) t_{i+1}*(n-i-2) ti+1(ni2)
那么 t i ∗ ( n − i − 1 ) + t i + 1 ∗ ( n − i − 2 ) t_i*(n-i-1)+t_{i+1}*(n-i-2) ti(ni1)+ti+1(ni2)为这两个人打水的等待成本
若将排在第 i + 1 i+1 i+1个人和第 i i i个人交换位置。
那么 t i ∗ ( n − i − 2 ) + t i + 1 ∗ ( n − i − 1 ) t_i*(n-i-2)+t_{i+1}*(n-i-1) ti(ni2)+ti+1(ni1)为这两个人交换位置后的等待成本
未交换位置和交换位置后的等待时间成本作差,可得 t i − t i + 1 t_i-t_{i+1} titi+1因为 t i > t i + 1 t_i>t_{i+1} ti>ti+1所以,交换位置前的等待时间成本大于交换位置后的,所以排队顺序中不应该存在排在前方的人的打水时间大于排在后方的人的打水时间的非单调递增的情况。

import java.io.*;
import java.util.*;

public class Main{
    static int N=100010;
    public static void main(String[] args)throws IOException{
        BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
        int n=Integer.parseInt(in.readLine());
        String[] strs=in.readLine().split(" ");
        int[] t=new int[N];
        for(int i=0;i<n;i++)
            t[i]=Integer.parseInt(strs[i]);
        Arrays.sort(t,0,n);
        long sum=0;
        for(int i=0;i<n;i++){
            sum+=t[i]*(n-i-1);
        }
        System.out.println(sum);
    }
}

货仓选址

在这里插入图片描述
在这里插入图片描述

import java.io.*;
import java.util.*;

public class Main{
    static int N=100010;
    static int[] loc=new int[N];
    public static void main(String[] args)throws IOException{
        BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
        int n=Integer.parseInt(in.readLine());
        String[] strs=in.readLine().split(" ");
        for(int i=0;i<n;i++)
            loc[i]=Integer.parseInt(strs[i]);
        Arrays.sort(loc,0,n);
        int d=loc[n/2];
        int res=0;
        for(int i=0;i<n;i++)
            res+=Math.abs(d-loc[i]);
        System.out.println(res);
    }
}

耍杂技的牛

在这里插入图片描述

题解

按照 w i + s i w_i+s_i wi+si从小到大的顺序排,最大的危险系数一定是最小的
假设存在 w i + s i > w i + 1 + s i + 1 w_i+s_i>w_{i+1}+s_{i+1} wi+si>wi+1+si+1
则有:

i i i个位置上的牛 i + 1 i+1 i+1个位置上的牛
交换前 w 1 + w 2 + . . . + w i − 1 − s i w_1+w_2+...+w_{i-1}-s_{i} w1+w2+...+wi1si w 1 + w 2 + . . . + w i − 1 + w i − s i + 1 w_1+w_2+...+w_{i-1}+w_i-s_{i+1} w1+w2+...+wi1+wisi+1
交换后 w 1 + w 2 + . . . + w i − 1 − s i + 1 w_1+w_2+...+w_{i-1}-s_{i+1} w1+w2+...+wi1si+1 w 1 + w 2 + . . . + w i − 1 + w i + 1 − s i w_1+w_2+...+w_{i-1}+w_{i+1}-s_i w1+w2+...+wi1+wi+1si

同时去掉 w 1 + w 2 + . . . + w i − 1 w_1+w_2+...+w_{i-1} w1+w2+...+wi1

i i i个位置上的牛 i + 1 i+1 i+1个位置上的牛
交换前 − s i -s_{i} si w i − s i + 1 w_i-s_{i+1} wisi+1
交换后 − s i + 1 -s_{i+1} si+1 w i + 1 − s i w_{i+1}-s_i wi+1si

同时加上 s i + s i + 1 s_i+s_{i+1} si+si+1

i i i个位置上的牛 i + 1 i+1 i+1个位置上的牛
交换前 s i + 1 s_{i+1} si+1 w i + s i w_i+s_i wi+si
交换后 s i s_{i} si w i + 1 + s i + 1 w_{i+1}+s_{i+1} wi+1+si+1

因为 w i > 1 w_i>1 wi>1,所以 w i + s i > s i w_i+s_i>s_i wi+si>si
因为假设的 w i + s i > w i + 1 + s i + 1 w_i+s_i>w_{i+1}+s_{i+1} wi+si>wi+1+si+1,所以综上 m a x ( s i + 1 , w i + s i ) > m a x ( s i , w i + 1 + s i + 1 ) max(s_{i+1},w_i+s_i)>max(s_i,w_{i+1}+s_{i+1}) max(si+1,wi+si)>max(si,wi+1+si+1)
交换前第 i i i个位置上的牛和第 i + 1 i+1 i+1个位置上的牛的最大风险值要大于交换后的第 i i i个位置上的牛和第 i + 1 i+1 i+1个位置上的牛的最大风险值。
所以综上来说,让 w i + s i w_i+s_i wi+si小的排上面这两头牛最大风险值更小,总体的排序也同理。

import java.io.*;
import java.util.*;

class Cow implements Comparable<Cow>{
    int w;
    int s;
    public Cow(int w,int s){
        this.w=w;
        this.s=s;
    }
    public int compareTo(Cow o){
        return Integer.compare(w+s,o.w+o.s);
    }
}

public class Main{
    static int N=50010;
    static Cow[] cow=new Cow[N];
    public static void main(String[] args)throws IOException{
        BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
        int n=Integer.parseInt(in.readLine());
        String[] strs;
        for(int i=0;i<n;i++){
            strs=in.readLine().split(" ");
            int w=Integer.parseInt(strs[0]);
            int s=Integer.parseInt(strs[1]);
            cow[i]=new Cow(w,s);
        }
        Arrays.sort(cow,0,n);
        int risk=-cow[0].s;
        int tw=cow[0].w;
        for(int i=1;i<n;i++){
            int res=tw-cow[i].s;
            tw+=cow[i].w;
            if(res>risk)risk=res;
        }
        System.out.println(risk);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
贪心算法是一种在每一步选择中都希望能找到局部最优解的算法。它通过贪心的选择策略,即每次选择当前情况下看似最优的解决方案,来逐渐构建整体的最优解。贪心算法在解决NPC类问题时,可以具有高效性和简洁性的优势。 在NPC类问题中,贪心算法可以用来解决各种优化问题,如最短路径问题、最小生成树问题和任务调度问题等。在涉及到路径问题时,可以通过每一步选择最短距离的方式来找到最短路径。而在最小生成树问题中,可以通过每次选择权重最小的边来构建整体的最小生成树。 举例来说,假设有一组任务需要安排在有限的资源下完成,每个任务有不同的时长和截止时间。这时可以使用贪心算法来解决任务调度问题。一种贪心的策略是选择当前剩余最短时长的任务进行安排,以尽量减少任务延迟。每次都选择剩余时长最短的任务,直到所有任务都安排完毕。 贪心算法在解决NPC类问题时并不一定能够得到全局最优解,但在一些问题中可以得到接近最优解的解决方案。此外,贪心算法通常具有计算复杂度较低的优势,能够快速求解问题,尤其在问题规模较小或具有特定特征时,贪心算法可以是一个简单而有效的解决方法。 总之,贪心算法通过局部最优选择来逐步构建整体最优解,在解决NPC类问题中可以得到不错的解决方案,并具有高效性和简洁性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值