九十六.贪心策略算法问题

题一:硬币支付问题
硬币问题

有1元,5元,10元,50元,100元,500元的硬币各c1,c5,c10,c50,c100,c500枚.

现在要用这些硬币来支付A元,最少需要多少枚硬币?

假定本题至少存在一种支付方案.

0≤ci≤10^9

0≤A≤10^9

输入:

第一行有六个数字,分别代表从小到大6种面值的硬币的个数

第二行为A,代表需支付的A元

样例:

输入

3 2 1 3 0 2
620

输出

6

import java.util.Scanner;

public class lianXI {
	
	static int[] cnts = new int[6];
	static int[] coins = {1, 5, 10, 50, 100, 500};
	
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		for(int i = 0; i<6; i++){
			cnts[i] = in.nextInt();
		}
		int A = in.nextInt();
		int res = f(A, 5);
		System.out.println(res);
	}
	
	public static int f(int A, int cur){
		if(A <= 0)
			return 0;
		if(cur == 0)
			return A;
		int coinValue = coins[cur];
		int x = A / coinValue;    //金额有多少个coinValue
		int cnt = cnts[cur];      //当前面值的硬币有cnt个
		int t = Math.min(x, cnt); 
		return t + f(A - t * coinValue, cur-1); //用t个当前面值,剩下的继续处理
	}
}

在这里插入图片描述
题二:快速渡河问题
A group of N people wishes to go across a river with only one boat, which can at most carry two persons.
Therefore some sort of shuttle arrangement must be arranged in order to row the boat back and forth so that all people may cross.
Each person has a different rowing speed; the speed of a couple is determined by the speed of the slower one.
Your job is to determine a strategy that minimizes the time for these people to get across.

Input

The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases.
Then T cases follow.
The first line of each case contains N, and the second line contains N integers giving the time for each people to cross the river.
Each case is preceded by a blank line. There won’t be more than 1000 people and nobody takes more than 100 seconds to cross.

Output

For each test case, print a line containing the total number of seconds required for all the N people to cross the river.

Sample Input
1
4
1 2 5 10
Sample Output
17

import java.util.Arrays;
import java.util.Scanner;

public class lianXI {
	
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int T = in.nextInt();
		for(int i = 0; i < T; i++){
			int n = in.nextInt();
			int[] speed = new int[n];
			for(int j = 0; j < n; j++){
				speed[j] = in.nextInt();
			}
			Arrays.sort(speed);
			f(n, speed);
		}		
	}
	
	public static void f(int n, int[]speed){
		int left = n;
		int ans = 0;
		while(left > 0){
			if(left == 1){
				ans += speed[0];
				break;
			}else if(left == 2){
				ans += speed[1];
				break;
			}else if(left == 3){
				ans += speed[2] + speed[0] + speed[1];
				break;
			}
			else{
				//1,2出发,1返回,最后两名出发,2返回
				int s1 = speed[1] + speed[0] + speed[left-1] + speed[1];
			   //1,3出发,1返回,1,4出发,1返回,1,2过河 
				int s2 = speed[left-2] + speed[left-1] + speed[0]*2;
				ans += Math.min(s1, s2);
				left -= 2;   //左侧是渡河的起点,left代表左侧的剩余人数
			}
		}
		System.out.println(ans);
	}
}


在这里插入图片描述
题六:区间调度问题
有n项工作,每项工作分别在si时间开始,在ti时间结束.

对于每项工作,你都可以选择参与与否.如果选择了参与,那么自始至终都必须全程参与.

此外,参与工作的时间段不能重复(即使是开始的瞬间和结束的瞬间的重叠也是不允许的).

你的目标是参与尽可能多的工作,那么最多能参与多少项工作呢?

1≤n≤100000

1≤si≤ti≤10^9

输入:

第一行:n
第二行:n个整数空格隔开,代表n个工作的开始时间
第三行:n个整数空格隔开,代表n个工作的结束时间

样例输入:

5
1 3 1 6 8
3 5 2 9 10

样例输出:

3

说明:选取工作1,3,5

import java.util.Arrays;
import java.util.Scanner;

public class lianXI {
	
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int[] s = new int[n];
		int[] t = new int[n];
		Job[] jobs = new Job[n];
		for(int i = 0; i < n; i++){
			s[i] = in.nextInt();
		}
		for(int i = 0; i < n; i++){
			t[i] = in.nextInt();
		}
		for(int j = 0; j < n; j++){
			jobs[j] = new Job(s[j],t[j]); 
		}
		Arrays.sort(jobs);
		int res = f(n,jobs);
		System.out.println(res);
	}
	
	public static int f(int n, Job[] jobs){
		int cnt = 1;
		int y = jobs[0].t;
		for(int i = 0; i < n; i++){
			if(jobs[i].s > y){
				cnt++;
				y = jobs[i].t;
			}
		}
		return cnt;
	}
	
	public static class Job implements Comparable<Job>{
		int s;
		int t;
		
		public Job(int s, int t){
			this.s = s;
			this.t = t;
		}
		
		@Override
		public int compareTo(Job other){
			int x = this.t - other.t;
			if(x == 0)
				return this.s - other.s;
			else
				return x;
		}
	}
}


在这里插入图片描述
题五:区间选点问题
Intervals
You are given n closed, integer intervals [ai, bi] and n integers c1, …, cn.
Write a program that:
reads the number of intervals, their end points and integers c1, …, cn from the standard input,
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,…,n,
writes the answer to the standard output.

Input
The first line of the input contains an integer n (1 <= n <= 50000) – the number of intervals.
The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai,
bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.

Output
The output contains exactly one integer equal to the minimal size of set Z
sharing at least ci elements with interval [ai, bi], for each i=1,2,…,n.
Sample Input
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
Sample Output
6

import java.util.Arrays;
import java.util.Scanner;

public class lianXI {
	
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		Interval[] intervals = new Interval[n];
		for(int i = 0; i < n; i++){
			intervals[i] = new Interval(in.nextInt(), in.nextInt(), in.nextInt());
		}
		Arrays.sort(intervals);  //按区间右端点排序
		
		int max = intervals[n-1].t; //右端极大值
		int[] axis = new int[max+1];  //标记数轴上的点是否已经被选中
		for(int i = 0; i < n; i++){
			//1、查阅区间有多少个点
			int s = intervals[i].s;  //起点
			int t = intervals[i].t;  //终点
			int cnt = sum(axis, s, t); //找到这个区间已经选点的数量,sums[t] - sums[s-1];
			//2、如果不够,从区间右端开始标记,遇标记过的就跳过
			intervals[i].c -= cnt;  //需要新增的点的数量
			while(intervals[i].c > 0){
				if(axis[t] == 0){  //从区间终点开始选点
					axis[t] = 1;
					intervals[i].c--;  //进一步减少需要新增的点的数量
					t--;
				}
				else{ //这个点已经被选过了
					t--;
				}
			} 
		}
		System.out.println(sum(axis,0, max));
	}
	
	public static int sum(int[] axis, int s, int t){
		int sum = 0;
		for(int i = s; i <= t; i++){
			sum += axis[i];
		}
		return sum;
	}
	
	public static class Interval implements Comparable<Interval>{
		int s;
		int t;
		int c;
		
		public Interval(int s, int t, int c){
			this.s = s;
			this.t = t;
			this.c = c;
		}
		
		public int compareTo(Interval other){
			int x = this.t - other.t;
			if(x == 0)
				return this.s - other.s;
			else
				return x;
		}
	}
}

在这里插入图片描述
题六:区间覆盖问题
Farmer John is assigning some of his N (1 <= N <= 25,000) cows to do some cleaning chores around the barn.

He always wants to have one cow working on cleaning things up and has divided the day into T shifts (1 <= T <= 1,000,000),

the first being shift 1 and the last being shift T.

Each cow is only available at some interval of times during the day for work on cleaning.

Any cow that is selected for cleaning duty will work for the entirety of her interval.

Your job is to help Farmer John assign some cows to shifts so that (i) every shift has at least one cow assigned to it,

and (ii) as few cows as possible are involved in cleaning. If it is not possible to assign a cow to each shift, print -1.

Input
Line 1: Two space-separated integers: N and T

Lines 2…N+1: Each line contains the start and end times of the interval during which a cow can work.

A cow starts work at the start time and finishes after the end time.
Output
Line 1: The minimum number of cows Farmer John needs to hire or -1 if it is not possible to assign a cow to each shift.
Sample Input
3 10
1 7
3 6
6 10
Sample Output
2

import java.util.Arrays;
import java.util.Scanner;

public class lianXI {
	
	public static void main(String[] args){
		
		Scanner in = new Scanner(System.in);
		int N = in.nextInt();
		int T = in.nextInt();
		Job[] jobs = new Job[N];
		for(int i = 0; i < N ;i++){
			jobs[i] = new Job(in.nextInt(), in.nextInt());
		}
		Arrays.sort(jobs);
		
		int start = 1;  //要覆盖的目标点,end覆盖该点的所有区间中右端点最右
		int end = 1;
		int ans = 1;
		for(int i = 0; i < N; i++){  
			int s = jobs[i].s;
			int t = jobs[i].t;
			if(i == 0 && s > 1) break;
			if(s <= start){    //当前区间有可能覆盖start
				end = Math.max(t, end);  //更新更右的端点
			}else{  //开始下一个区间
				ans++;  //上一个目标覆盖已经达成,计数加1
				start = end + 1;  // 更新起点,设置一个新的覆盖目标
				if(s <= start){
					end = Math.max(t, end);
				}else{
					break;
				}
			}
			if(end >= T){  //当前的end超越了线段的右端
				break;
			}
		}
		if(end < T)
			System.out.println(-1);
		else
			System.out.println(ans);
	}
	
	public static class Job implements Comparable<Job>{
		int s;
		int t;
		
		public Job(int s, int t){
			this.s = s;
			this.t = t;
		}
		
		@Override
		public int compareTo(Job other){
			int x = this.s - other.s;
			if(x == 0)
				return this.t - other.t;
			else
				return x;
		}
	}
}


在这里插入图片描述
题七:字典序最小问题
给一个定长为N的字符串S,构造一个字符串T,长度也为N。

起初,T是一个空串,随后反复进行下列任意操作

  1. 从S的头部删除一个字符,加到T的尾部
  2. 从S的尾部删除一个字符,加到T的尾部

目标是最后生成的字符串T的字典序尽可能小

1≤N≤2000
字符串S只包含大写英文字母

输入:字符串S
输出:字符串T
要求每80个字符换行输出

import java.util.Arrays;
import java.util.Scanner;

public class lianXI {
	
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		StringBuilder ss = new StringBuilder();
		for(int i = 0; i < n; i++){
			ss.append(in.next());
		}
		f(ss.toString());
	}
	
	public static void f(String s){
		String s1 = new StringBuilder(s).reverse().toString();
		int N = s.length();
		StringBuilder rs = new StringBuilder();
		int cnt = 0;
		while(rs.length() < N){
			if(s.compareTo(s1) <= 0){
				rs.append(s.charAt(0));
				s = s.substring(1);
			}else{
				rs.append(s1.charAt(0));
				s1 = s1.substring(1);
			}
			//字符满80个就换行
		      if (rs.length() % 80 == 0) {
		        System.out.println(rs.substring(cnt * 80, (cnt + 1) * 80));
		        cnt++;
		      }
		    }
		    //余数部分
		    if (rs.length() > cnt * 80) {
		      System.out.println(rs.substring(cnt * 80));
		    }
		}
    }


在这里插入图片描述
题八:最优装载问题
给出n个物体,第i个物体重量为wi。选择尽量多的物体,使得总重量不超过C。

import java.util.Arrays;
import java.util.Scanner;

public class lianXI {
	
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int c = in.nextInt();
		int[] w = new int[n];
		for(int i = 0; i < n; i++){
			w[i] = in.nextInt();
		}
		Arrays.sort(w);
		int res = f(n, w, c);
		System.out.println(res);
	}
	
	public static int f(int n, int[]w, int c){
		int sum = 0;
		int cnt = 0;
		for(int i = 0; i < n; i++){
			sum += w[i];
			if(sum <= c){
				cnt++;
			}else{
				break;
			}
		}
		return cnt;
	}
}

在这里插入图片描述

题九:部分背包问题
有n个物体,第i个物体的重量为wi,价值为vi。在总重量不超过C的情况下让总价值尽量高。

每一个物体都可以只取走一部分,价值和重量按比例计算。

求最大总价值

注意:每个物体可以只拿一部分,因此一定可以让总重量恰好为C。

 import java.util.Arrays;
import java.util.Scanner;

public class lianXI {
	
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int[] w = new int[n];
		int[] v = new int[n];
		for(int i = 0; i < n; i++){
			w[i] = in.nextInt();
		}
		for(int j = 0; j < n; j++){
			v[j] = in.nextInt();		
		}
		Obj[] obj = new Obj[n];
		for(int i = 0; i < n; i++){
			obj[i] = new Obj(w[i],v[i]);
		}
		Arrays.sort(obj);
		double C = in.nextDouble();
	    f(n,obj,C);
	}
	
	public static void f(int n, Obj[] obj, double C){
		double c = C;
		int maxValue = 0;
		for(int i = n-1; i>=0; i--){
			if(obj[i].w <= c){
				maxValue += obj[i].v;
				c -= obj[i].w;
			}else{
				maxValue += obj[i].v * (c / obj[i].w);
				break;
			}
		}
		System.out.println(maxValue);
	}
	
	public static class Obj implements Comparable<Obj>{
		int w ;
		int v ;
		public Obj(int w, int v){
			this.w = w;
			this.v = v;
		}
        
		public double getPrice(){
			return v / (double)w;
		}
		@Override
		public int compareTo(Obj o){
			if(this.getPrice() == o.getPrice()) return 0;
			else if(this.getPrice() < o.getPrice()) return -1;
			else return 1;
		}
		
	}
}

在这里插入图片描述
题十:乘船问题
有n个人,第i个人重量为wi。每艘船的最大载重量均为C,且最多只能乘两个人。用最少的船装载所有人。

贪心策略:考虑最轻的人i,如果每个人都无法和他一起坐船(重量和超过C),则唯一的方案是每个人坐一艘
否则,他应该选择能和他一起坐船的人中最重的一个j

求需要船的数量

import java.util.Arrays;
import java.util.Scanner;

public class lianXI {
	
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int[] w = new int[n];
		for(int i = 0; i < n; i++){
			w[i] = in.nextInt();
		}
		int c = in.nextInt();
		Arrays.sort(w);
		
		int cntOfPerson = n;
		int cntOfBoat = 0;
		int p1 = 0;
		int p2 = n-1;
		while(cntOfPerson > 0){
			if(w[p1] + w[p2] > c){
				p2--;
				cntOfPerson--;
				cntOfBoat++;
			}else{
				p1++;
				p2--;
				cntOfPerson -= 2;
				cntOfBoat ++;
			}
		}
		System.out.println(cntOfBoat);
	}
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值