CCF计算机职业资格认证考试练习——20180902买菜(Java实现)

问题描述

  小H和小W来到了一条街上,两人分开买菜,他们买菜的过程可以描述为,去店里买一些菜然后去旁边的一个广场把菜装上车,两人都要买n种菜,所以也都要装n次车。具体的,对于小H来说有n个不相交的时间段[a1,b1],[a2,b2]...[an,bn]在装车,对于小W来说有n个不相交的时间段[c1,d1],[c2,d2]...[cn,dn]在装车。其中,一个时间段[s, t]表示的是从时刻s到时刻t这段时间,时长为t-s。
  由于他们是好朋友,他们都在广场上装车的时候会聊天,他们想知道他们可以聊多长时间。

输入格式

  输入的第一行包含一个正整数n,表示时间段的数量。
  接下来n行每行两个数ai,bi,描述小H的各个装车的时间段。
  接下来n行每行两个数ci,di,描述小W的各个装车的时间段。

输出格式

  输出一行,一个正整数,表示两人可以聊多长时间。

样例输入

4
1 3
5 6
9 13
14 15
2 4
5 7
10 11
13 14

样例输出

3

数据规模和约定

  对于所有的评测用例,1 ≤ n ≤ 2000, ai < bi < ai+1,ci < di < ci+1,对于所有的i(1 ≤ i ≤ n)有,1 ≤ ai, bi, ci, di ≤ 1000000。

解题思路

思考之后觉得,解决这个问题应该就是把问题拆成几种情况,对每个时间段分情况讨论。

一开始觉得只有下面两种情况是可以增加聊天时间的,其余都不行:

1、小H的起始点位于小W的时间段中间(判断条件左闭右开)

(1)小H的结束点位于小W的时间段中间

(2)小H的结束点位于小W的结束点右边

2、小W的起始点位于小H的时间段中间(判断条件左闭右开)

(1)小W的结束点位于小H的时间段中间

(2)小W的结束点位于小H的结束点右边

于是分情况讨论出了下面的代码:

import java.util.Scanner;

public class Main {
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int time = 0;
		int[][] H = new int[n][2];
		int[][] W = new int[n][2];
		for(int i=0;i<n;i++) {
			H[i][0] = sc.nextInt();
			H[i][1] = sc.nextInt();
		}
		for(int i=0;i<n;i++) {
			W[i][0] = sc.nextInt();
			W[i][1] = sc.nextInt();
		}
		for(int i=0;i<n;i++) {
			if(H[i][0]>=W[i][0] && H[i][0]<W[i][1]) {
				if(H[i][1]<W[i][1]) {
					time += H[i][1]-H[i][0];
				}
				else {
					time += W[i][1]-H[i][0];
				}
			}
			else if(W[i][0]>=H[i][0] && W[i][0]<W[i][1]) {
				if(W[i][1]<H[i][1]) {
					time += W[i][1]-W[i][0];
				}
				else {
					time += H[i][1]-W[i][0];
				}
			}
			else {
				break;
			}
		}
		System.out.println(time);
	}
}

在eclipse中自己测试了一下,使用了题中所给的输入样例,发现可以正确输出,然后兴高采烈地放到了网页上检测,结果显示错误!

思前想后搞不懂为什么会错误,明明输入和输出都跟样例一样了呀!

后来又是借鉴了一篇博客,才想明白自己到底哪里出错了:解决问题时根本没有把所有地情况全部考虑到!

举个例子:如果小H某次时间跨度是 [9,14] ,而小W某两次时间跨度是 [10,11] 和 [13,14] ,那么小H就可以包含两次小W的时间跨度!然而在上面的代码中并不能做到这一点,上面的代码会这么运行:[9,14] 和 [10,11] 进行比较,发现覆盖了 [10,11] ,然后就会进入下一个循环,计算 [15,16] 和 [13,14] 之间的关系,结果没有重复,就不会记录 [13,14] 这次的聊天时间!

发现问题之后就很好办了,改变思路,多进行一次for循环就可以了。代码如下:

import java.util.Scanner;

public class Main {
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int time = 0;
		int[][] H = new int[n][2];
		int[][] W = new int[n][2];
		for(int i=0;i<n;i++) {
			H[i][0] = sc.nextInt();
			H[i][1] = sc.nextInt();
		}
		for(int i=0;i<n;i++) {
			W[i][0] = sc.nextInt();
			W[i][1] = sc.nextInt();
		}
		for(int h=0;h<n;h++) {
			for(int w=0;w<n;w++) {
				if(H[h][0]<=W[w][0]) {
					if(H[h][1]>W[w][0]&&H[h][1]<=W[w][1]) {
						time += H[h][1]-W[w][0];
					}
					else if(H[h][1]>W[w][1]) {
						time += W[w][1]-W[w][0];
					}
				}
				else if(H[h][0]>W[w][0]&&H[h][0]<W[w][1]) {
					if(H[h][1]<=W[w][1]) {
						time += H[h][1]-H[h][0];
					}
					else if(H[h][1]>W[w][1]) {
						time += W[w][1]-H[h][0];
					}
				}
			}
		}
		System.out.println(time);
	}
}

运行。正确。时间使用:406ms,空间使用31.25MB

在网上还看到了一篇博客,其中将正确代码进行了优化,提前终止了不必要的循环。

附上链接:https://blog.csdn.net/qq_29110265/article/details/83511790

猜你喜欢

转载自blog.csdn.net/qq_38813668/article/details/85015528