這是一道競賽的題目,如下:
在編寫圖形界面軟件的時候,經常會遇到處理兩個矩形的關系。
如圖【1.jpg】所示,矩形的交集指的是:兩個矩形重疊區的矩形,當然也可能不存在(參看【2.jpg】)。兩個矩形的並集指的是:能包含這兩個矩形的最小矩形,它一定是存在的。

本題目的要求就是:由用戶輸入兩個矩形的坐標,程序輸出它們的交集和並集矩形。
矩形坐標的輸入格式是輸入兩個對角點坐標,注意,不保證是哪個對角,也不保證順序(你可以體會一下,在桌面上拖動鼠標拉矩形,4個方向都可以的)。
輸入數據格式:
x1,y1,x2,y2
x1,y1,x2,y2
數據共兩行,每行表示一個矩形。每行是兩個點的坐標。x坐標在左,y坐標在右。坐標系統是:屏幕左上角為(0,0),x坐標水平向右增大;y坐標垂直向下增大。
要求程序輸出格式:
x1,y1,長度,高度
x1,y1,長度,高度
也是兩行數據,分別表示交集和並集。如果交集不存在,則輸出“不存在”
前邊兩項是左上角的坐標。后邊是矩形的長度和高度。
例如,用戶輸入:
100,220,300,100
150,150,300,300
則程序輸出:
150,150,150,70
100,100,200,200
例如,用戶輸入:
10,10,20,20
30,30,40,40
則程序輸出:
不存在
10,10,30,30
題目給人的第一感覺並不是很難,但可能繁瑣~~
我的第一種想法就是先求“並集矩形”因為這個會很好求,那用什么數據結構來表示呢?
顯然,保存矩形的四個頂點咯,用一個Point類來保存:
class Point { int x; int y; }
但,仔細想一想,實際上我們並不需要太多的數據!
我們要確定一個矩形,只需要矩形的起始x坐標、結束x坐標、起始y坐標和結束y坐標。文字不好說,看圖吧:

所以,保存一個矩形類我們可以這樣寫:
class Rect { public int startX; public int endX; public int startY; public int endY; }
題目中,x1,y1和x2,y2這兩個點並不一定是從左上角到右下角這兩個點,但一定是對角線上的!所以根據大小關系還是很好確定的:
public Rect(String str) { String[] l = str.split(","); int x1 = Integer.parseInt(l[0]); int y1 = Integer.parseInt(l[1]); int x2 = Integer.parseInt(l[2]); int y2 = Integer.parseInt(l[3]); startX = x1 < x2 ? x1 : x2; endX = x1 > x2 ? x1 : x2; startY = y1 < y2 ? y1 : y2; endY = y1 > y2 ? y1 : y2; }
一個可以從字符串直接生成矩形的構造方法~~~。

從上圖不難看出,“並集矩形”的startX是由矩形1和矩形2的startX中比較小的那個來決定的,endX由比較大的endX決定。所以,“並集矩形”的求法就很簡單了:
// 由兩個矩形構造出他們的“並集矩形” public Rect(Rect r1, Rect r2) { startX = r1.startX < r2.startX ? r1.startX : r2.startX; endX = r1.endX > r2.endX ? r1.endX : r2.endX; startY = r1.startY < r2.startY ? r1.startY : r2.startY; endY = r1.endY > r2.endY ? r1.endY : r2.endY; }
“交集矩形”貌似就麻煩多了,有幾種情況要進行判斷。

觀察圖中的紅色框,可以得到一個簡單的結論:“交集矩形”的startX由較大的startX決定、endX由較小的endX決定,Y也是同樣的情況。
但是,對於沒有交集的情況呢?

我們用上面的方法進行推導,“交集矩形”的startX就是藍色矩形的startX,endX就是綠色矩形的endX。顯然,startX大於endX。這樣的矩形應該是不存在的。對於Y軸應該也是同樣的情況。
找到了規律求解也就不難了,所有代碼如下:
public class Test { public static void main(String[] args) { Rect r1 = new Rect("100,220,300,100"); Rect r2 = new Rect("150,150,300,300"); Rect merge = new Rect(r1, r2); Rect both = Rect.getBothArea(r1, r2); both.printInfo(); merge.printInfo(); System.out.println("~~~~~~~~~~~~~~~~~~~~~~"); r1 = new Rect("10,10,20,20"); r2 = new Rect("30,30,40,40"); merge = new Rect(r1, r2); both = Rect.getBothArea(r1, r2); both.printInfo(); merge.printInfo(); } } class Rect { public int startX; public int endX; public int startY; public int endY; public Rect() { } // 由兩個矩形構造出他們的“並集矩形” public Rect(Rect r1, Rect r2) { startX = r1.startX < r2.startX ? r1.startX : r2.startX; endX = r1.endX > r2.endX ? r1.endX : r2.endX; startY = r1.startY < r2.startY ? r1.startY : r2.startY; endY = r1.endY > r2.endY ? r1.endY : r2.endY; } public static Rect getBothArea(Rect r1, Rect r2) { Rect merge = new Rect(r1, r2); Rect both = new Rect(); both.startX = r1.startX == merge.startX ? r2.startX : r1.startX; both.endX = r1.endX == merge.endX ? r2.endX : r1.endX; both.startY = r1.startY == merge.startY ? r2.startY : r1.startY; both.endY = r1.endY == merge.endY ? r2.endY : r1.endY; return both; } public Rect(String str) { String[] l = str.split(","); int x1 = Integer.parseInt(l[0]); int y1 = Integer.parseInt(l[1]); int x2 = Integer.parseInt(l[2]); int y2 = Integer.parseInt(l[3]); startX = x1 < x2 ? x1 : x2; endX = x1 > x2 ? x1 : x2; startY = y1 < y2 ? y1 : y2; endY = y1 > y2 ? y1 : y2; } public void printInfo() { if (startX >= endX || startY >= endY) { System.out.println("不存在"); } else { System.out.println(startX + "," + startY + "," + (endX - startX) + "," + (endY - startY)); } } }
代碼比想象中的少得多了~~~
后記:一開始先分析題目,找出解題的突破口比一上來就蠻干要強得多!記得自己第一次做這題就是沒仔細思考,用四個Point來保存矩形,最后,關系太多,把自己給繞暈了~~~
yjiyjige 2013.4.20
