JAVA编程(贪心法)——POJ1328 & POJ2586

 poj1328 Radar Installation

/*
 * Author: poj_whut_shz
 * Problem: Radar Installation
 * Code: poj_1328
 * URL: http://poj.org/problem?id=1328
 * Data: 2019/9/5
 */

/*
 *  【题意分析】:
 *  给定一个直角坐标系,定义x轴为海岸线,海岸线上方是海,下方是陆地.	  
 *  在海域零星分布一些海岛, 需要要在海岸线上安装若干个雷达覆盖这些海岛,
 *  每个雷达的覆盖半径都是相同且固定的.
 *  
 *  输入:海岛的个数n,雷达的覆盖半径d,每个海岛的坐标
 *  输出:覆盖所有海岛所需的最小雷达数
 *  
 *  【解题思路】:
 *  1)计算覆盖每个海岛雷达需放置的坐标区间
 *  2)将坐标区间按左端点坐标从小到大进行排序
 *  3)
 *  	① 在第一个区间A的右端点 A.R放置一个点,总放置点数加一
 *  	② 若下一个区间B的左端点 B.L > A.R, 则区间A与区间B无交集,此时在区间B的右端点 B.R放置一个点,总放置点数加一
 *  	    否则说明区间A与区间B相交, 此时进一步判断,若 B.R < A.R,说明 区间B 在 区间A 的内部,此时把原本放置在 A.R的点移动到 B.R,总放置点数不变
 *  	③ 重复这个过程直到所有区间被遍历完成
 */
package basic;

import java.util.Scanner;
import java.lang.Math;

public class P1328 {
	
	public static int island = 0;  //海岛的个数
	public static int radius = 0;  //雷达的半径
	
	public static int x = 0;  //海岛的x坐标
	public static int y = 0;  //海岛的y坐标
	
	public static double[][] intervals;  //覆盖每个海岛雷达需放置的坐标区间
	
	public static boolean isSolve = true;  //是否有解
	
	//将坐标区间按左端点坐标从小到大进行排序
	public static void sort(double[][] intervals, int size) {
        double[] temp = new double[2];
        
        for(int i = 0 ; i < size - 1; i ++) {
        	for(int j = 0 ;j < size - 1 - i ; j++) {
        		if(intervals[j][0] > intervals[j + 1][0]) {  //交换两数位置
        			temp[0] = intervals[j][0];
        			temp[1] = intervals[j][1];
        			
        			intervals[j][0] = intervals[j + 1][0];
        			intervals[j][1] = intervals[j + 1][1];
        			
        			intervals[j + 1][0] = temp[0];
        			intervals[j + 1][1] = temp[1];
        		}
        	}
        }
	}
	
	//计算最少雷达数
	public static int solve(double[][] intervals, int size) {
		sort(intervals, size); //将坐标区间按左端点坐标从小到大进行排序
		for(int i = 0; i < size; i++) {
			System.out.println(intervals[i][0] + " " + intervals[i][1]);
		}
		int minPoint = 1; //最小雷达数
		
		double right = intervals[0][1];
		for(int i = 1; i < size; i++) {
			if(intervals[i][0] > right) {  //区间i与区间i-1无交集
				minPoint++;
				right = intervals[i][1];
				
			}
			else if(intervals[i][1] < right) {  //区间i在区间i-1内部
				right = intervals[i][1];
			}
			else {
				// 无需操作,区间i与区间i-1相交
			}
		}
		return minPoint;
	}
	
	
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		int testCase = 0;
		while(scan.hasNext()) {
			island = scan.nextInt();  //海岛的个数
			radius = scan.nextInt();  //雷达的半径
			
			if(island != 0 && radius != 0) {  //未结束时则执行
				intervals = new double[island][2];
				
				for(int i = 0; i < island; i++) {  //循环计算覆盖每个海岛雷达需放置的坐标区间
					x = scan.nextInt();  //海岛的x坐标
					y = scan.nextInt();  //海岛的y坐标
					
					//海岛位置超过雷达覆盖半径
					if(y > radius) {
						isSolve = false;
					}
					else {
						double offset = Math.sqrt(radius * radius - y * y);  //勾股定理
						intervals[i][0] = x - offset;  //左端点
						intervals[i][1] = x + offset;  //右端点
					}
				}
				int minRadar = (isSolve ? solve(intervals, island) : -1);  //计算最少雷达数
				System.out.println("Case " + (++testCase) + ": " + minRadar);  //输出最少雷达数
			}
		}
		scan.close();
	}
}

poj2586

/*
 * Author: poj_whut_shz
 * Problem: Radar Installation
 * Code: poj_2686
 * URL: http://poj.org/problem?id=2586
 * Data: 2019/9/5
 */

/*
 *  【题意分析】:
 *  已知一个公司在某一年中,每个月要么固定盈利s、要么固定亏损d。
 *  但是具体哪个月盈利、那个月亏损却不得而知。
 *  不过可以肯定的是,这一年中,任意的连续5个月盈亏和必定是亏损(< 0)。
 *  问这年是否存在盈利的可能,若可能盈利,【最大的盈利额】是多少?
 *  
 *  输入:盈利s和亏损d
 *  输出:最大盈利额
 *  
 *  【解题思路】:
 *  由于组合情况较少,可以把每5个月的所有盈亏组合情况列举出来:
 *  	① 当 s >= 4d时,即1个月的盈利抵得上4个月的亏损
 *  	无论如何组合,都无法满足【连续5月必亏损】的前提
 *  	因此为了满足这种情况,只可能所有月份均亏损 
 *  	即亏损月份为 [1-12],全年无利润
 *   	② 当 s < 4d但2s >= 3d时,即1个月的盈利刚好小于4个月的亏损
 *   	此时只需保证每连续5个月至少有4个月是亏损即可
 *   	根据贪心逻辑,全年盈亏月份为:sddddsddddsd
 *   	全年最大利润为: 3s - 9d
 *   	③ 当 2s < 3d但3s >= 2d时,即2个月的盈利刚好小于3个月的亏损
 *   	此时只需保证每连续5个月至少有3个月是亏损即可
 *   	根据贪心逻辑,全年盈亏月份为:ssdddssdddss
 *   	全年最大利润为: 6s - 6d
 *   	④ 当 3s < 2d但4s >= d时,即3个月的盈利刚好小于2个月的亏损
 *   	此时只需保证每连续5个月至少有2个月是亏损即可
 *   	根据贪心逻辑,全年盈亏月份为:sssddsssddss
 *   	全年最大利润为: 8s - 4d
 *   	⑤ 当 4s < d 时,即4个月的盈利刚好小于1个月的亏损
 *   	此时只需保证每连续5个月至少有1个月是亏损即可
 *   	根据贪心逻辑,全年盈亏月份为:ssssdssssdss
 *   	全年最大利润为: 10s - 2d
 */
package basic;

import java.util.Scanner;

public class P2586 {

	public static void main(String[] args) {
		int s, d;
		Scanner scan = new Scanner(System.in);
		while(scan.hasNext()) {
			s = scan.nextInt();
			d = scan.nextInt();
			
			int surplus = 0;	// 全年盈余
			if(4 * s < d) {
				surplus = 10 * s - 2 * d;
			}
			else if(3 * s < 2 * d) {
				surplus = 8 * s - 4 * d;
			}
			else if(2 * s < 3 * d) {
				surplus = 6 * s - 6 * d;
			}
			else if(s < 4 * d) {
				surplus = 3 * s - 9 * d;
			}
			else {
				surplus = -1;
			}
			if(surplus <= 0) {
				System.out.println("Deficit");
			}
			else {
				System.out.println(surplus);
			}
		}
		scan.close();
	}

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值