[Java] [刷題] 校門外的樹


題目

某校大門外長度為L的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1米。我們可以把馬路看成一個數軸,馬路的一端在數軸0的位置,另一端在L的位置;數軸上的每個整數點,即0,1,2,……,L,都種有一棵樹。

由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表示。已知任一區域的起始點和終止點的坐標都是整數,區域之間可能有重合的部分。現在要把這些區域中的樹(包括區域端點處的兩棵樹)移走。你的任務是計算將這些樹都移走后,馬路上還有多少棵樹。

輸入

第一行有兩個整數L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表馬路的長度,M代表區域的數目,L和M之間用一個空格隔開。

接下來的M行每行包含兩個不同的整數,用一個空格隔開,表示一個區域的起始點和終止點的坐標。

500 3
150 300
100 200
470 471

輸出

輸出包括一行,這一行只包含一個整數,表示馬路上剩余的樹的數目。

298

來源

NOIP 2005年普及組第二題,收錄於NOIPOJ第380題

解題思路

題目第一句非常具有迷惑性,極其容易讓人聯想到數組長度就是L,實際上這里的長度指數軸上的長度,即0到L的距離,但在求解過程中,將0到L存入數組,總計存入L+1個數(數組長度)。

0到1的距離為1,0到1有2個數;
0到2的距離為2,0到2有3個數;
0到100的距離為100,0到100有101個數;
……
0到L的距離為L,0到L有L+1個數。

我的解法是將所有區間抽象為起點和終點,並疊加到一條線段上。

我將某一個起點記為+1,某一個終點記為-1,其余位置記為0,並使用一維數組trees來存儲這條線段(即存儲區間起點和終點的的疊加值)。

若兩個起點位置相同,則疊加得到+2;若兩個終點位置相同,則疊加得到-2;若某一個起點和某一個終點位置相同(兩個區間合並為一個區間),則疊加得到0。

存儲完所有區間后,遍歷這條線段上的疊加結果,在遍歷時將每個疊加結果依次累加到變量stack中。

因為起點和終點必然成對存在,即+1和-1的個數必定相等,那么當沒有進入或已經離開所有區間的時候,stack必定為0,而只要遍歷位置在任意一個區間時,累加的stack必定大於0(按我定義的正負來說)。

package top.qlin.leo;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sr = new Scanner(System.in);

		/** 馬路上的樹(沒有移走之前),總共有L+1棵。 */
		byte[] trees = new byte[sr.nextInt() + 1];

		/** 區域個數。用於確定循環次數。 */
		int time = sr.nextInt();

		// 循環time次,讀取所有“區域”。
		// 如果某區域的終點和另一個區域的起點重疊,這種方法可以自動合並兩個區域。
		for (int t = 0; t < time; t++) {
			trees[sr.nextInt()]++;    // 這里輸入的int是該區域的起點位置。
			trees[sr.nextInt()]--;    // 這里輸入的int是區域的終點位置。
		}

		sr.close();

		/** 某一位置的“樹”身處的區域的個數。 */
		int stack = 0,

		/** 當前未被移走的樹的數量 */
			quantity = 0;

		// 遍歷trees以統計剩余樹的數量。
		for (int i = 0; i < trees.length; i++) {
			// stack != 0表示第i棵樹身處stack個疊加的區域中。
			// trees[i] != 0表示第i棵樹不在區域的兩個端點上。
			if (trees[i] != 0 || stack != 0) {
				stack += trees[i];
			} else {
				quantity++;
			}
		}
		System.out.print(quantity);
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM