线段覆盖问题

线段覆盖

       给定x轴上的N(0<N<100)条线段,每个线段由它的二个端点a_I和b_I确定,I=1,2,……N.这些坐标都是区间(-999,999)的整数。有些线段之间会相互交叠或覆盖。请你编写一个程序,从给出的线段中去掉尽量少的线段,使得剩下的线段两两之间没有内部公共点。所谓的内部公共点是指一个点同时属于两条线段且至少在其中一条线段的内部(即除去端点的部分)。

输入描述 Input Description

    输入第一行是一个整数N。接下来有N行,每行有二个空格隔开的整数,表示一条线段的二个端点的坐标。

输出描述 Output Description

    输出第一行是一个整数表示最多剩下的线段数。

样例输入 Sample Input

3

6  3

1  3

2  5

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

0<N<100

基础线段覆盖模型 -> 贪心

直接按照右端点从小到大排序。优先选排在前面的。

证明:排序后显然当你选了一个线段后,再要从后面选一个线段,其左断点必须>=你的右端点。右端点当然越小越好。

代码如下:

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 = 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]);
    }
  }

}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值