线段覆盖问题

线段覆盖
给定x轴上的N(0 输入描述 Input Description
输入第一行是一个整数N。接下来有N行,每行有二个空格隔开的整数,表示一条线段的二个端点的坐标。
输出描述 Output Description
输出第一行是一个整数表示最多剩下的线段数。
样例输入 Sample Input
3
63
13
25
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
0

基础线段覆盖模型 -> 贪心
直接按照右端点从小到大排序。优先选排在前面的。
证明:排序后显然当你选了一个线段后,再要从后面选一个线段,其左断点必须>=你的右端点。右端点当然越小越好。
代码如下:
public class Test {private static void quickSort(int[][] arr, int low, int high){ if (low >= high || arr.length == 0) return; int i = low; int j = high; int x = arr[low][1]; while (i < j){ //从右向左查找第一个小于x的坐标 while (i < j && arr[j][1] > x) j--; //从左向右查找第一个大于x的坐标 while (i < j && arr[i][1] <= x) i++; if (i < j){ int p1 = arr[i][1]; int p2 = arr[i][0]; arr[i][1] = arr[j][1]; arr[i][0] = arr[j][0]; arr[j][1] = p1; arr[j][0] = p2; } }int tmp1 = arr[i][1]; int tmp2 = arr[i][0]; arr[i][1] = arr[low][1]; arr[i][0] = arr[low][0]; arr[low][1] = tmp1; arr[low][0] = tmp2; //左排 quickSort(arr, low, i-1); //右排 quickSort(arr, i+1, high); }public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请输入行数:"); int lineNum = scan.nextInt(); System.out.println("请输入线段起始:"); scan.nextLine(); int[][] array = new int[lineNum][2]; for (int i = 0; i < lineNum; i++){ String[] str = scan.nextLine().split(" +"); if (Integer.parseInt(str[0]) < Integer.parseInt(str[1])){ array[i][0] = Integer.parseInt(str[0]); array[i][1] = Integer.parseInt(str[1]); } else { array[i][0] = Integer.parseInt(str[1]); array[i][1] = Integer.parseInt(str[0]); } } scan.close(); quickSort(array, 0, lineNum - 1); int prev = 0; int count = 1; for (int j = 1; j < lineNum; j++){ if (array[prev][1] <= array[j][0]){ count++; prev = j; } } System.out.println(count); } }

注意:在调用nextLine()函数前调用了Scanner的另一个函数nextInt(),这会导致调用nextLine()的时候获取不到输入的值,这时候在要使用nextLine()前先调用一次nextLine(),这样留在缓冲区的“回车符”就会被处理掉,这时第二个nextLine()函数可以正常读取到数据。具体原因可参考:Java中nextInt()后接nextLine()读取不到数据
线段覆盖2
题目描述 Description
数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~1000000,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。
n<=1000
输入描述 Input Description
第一行一个整数n,表示有多少条线段。
接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。
输出描述 Output Description
输出能够获得的最大价值
样例输入 Sample Input
【线段覆盖问题】3
1 2 1
2 3 2
1 3 4
样例输出 Sample Output
4
数据范围
对于100%的数据,n≤1000;0<=ai,bi<=10000000<=ci<=1000000
基于贪心的基础上,排序DP
代码如下:
public class Test {/** * 根据线段右边界值进行快排。 * @param array * @param low * @param high */ public static void quickSort(int[][] array, int low, int high){ if (low <= high || array.length == 0) { return; } int i = low; int j= high; int key = array[low][1]; while (i < j){ //从右向左查找第一个小与key的坐标 while (i < j && array[j][1] > key){ j--; } //从左向右查找第一个大与key的坐标 while (i < j && array[i][1] >= key){ i++; } if (i < j){ int p0 = array[i][0]; int p1 = array[i][1]; int p2 = array[i][2]; array[i][0] = array[j][0]; array[i][1] = array[j][1]; array[i][2] = array[j][2]; array[j][0] = p0; array[j][1] = p1; array[j][2] = p2; } }//保证array[low][]始终存放最小值 int tmp0 = array[i][0]; int tmp1 = array[i][1]; int tmp2 = array[i][2]; array[i][0] = array[low][0]; array[i][1] = array[low][1]; array[i][2] = array[low][2]; array[low][0] = tmp0; array[low][1] = tmp1; array[low][2] = tmp2; quickSort(array, low, i-1); quickSort(array, i+1, high); }public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请输入线段总数:"); int lineNum = scan.nextInt(); scan.nextLine(); System.out.println("请输入线段信息(中间空格隔开):"); int[][] arr = new int[lineNum][3]; for (int i = 0; i < lineNum; i++){ String[] str = scan.nextLine().split(" "); arr[i][0] = Integer.parseInt(str[0]); arr[i][1] = Integer.parseInt(str[1]); arr[i][2] = Integer.parseInt(str[2]); } scan.close(); quickSort(arr, 0, lineNum-1); //存放(按右端点升序排序后的)以每条线段为右边界的线段最大价值 int[] maxValue = https://www.it610.com/article/new int[1000]; //以第0条线段为右边界的线段最大价值大为第0条线段本身的价值 maxValue[0] = arr[0][2]; //从第一条线段开始遍历 for (int m = 1; m < lineNum; m++){ //先将以该线段为右边界的线段最大价值为以前一条线段为右边界的线段的最大值 maxValue[m] = maxValue[m-1]; //遍历该条线段之前的线段 for (int n = m-1; n>= 0; n--){ //找出第一条与该线段不重合的线段,即某条右端点小于该条线段的左端点的线段 if (arr[n][1] < arr[m][0]){ //如果前面一条与该线段不重合的线段的最大价值加该条线段的价值大于上一条线段的价值 if (arr[m][2] + maxValue[n] > maxValue[m-1]){ //以该条线段为右边界的线段最大价值赋为前面第一条与该条线段不重合的线段的最大价值加该条线段的价值 maxValue[m] = arr[n][2] + maxValue[n]; } break; } } } //数组maxValue中的每个值代表的就是以每条线段为右边界的线段最大价值 for(int i = 0; i < lineNum; i++){ System.out.println("以第" + i + "条线段为边界的线段的最大价值为:" + maxValue[i]); } }}



    推荐阅读