聽說這道題用矩形切割做,於是學習了2004薛矛的oi論文。
我的做法是:弄一個白紙集合,開始裡面只有一張白紙(0,0) (A,B)。然後把輸入的N個矩形倒序地,每一個都與白紙集合中的所有白紙依次切割。對於輸入的矩形rec[i]與每張白紙,用rec[i]去覆蓋它。如果有交集,則交集為rec[i]的顏色,把元素個數統計到rec[i]的顏色中,然後把白紙中沒被覆蓋的地方切成矩形加入到白紙集合,並且把原來被切的白紙從集合中刪除。沒有交集就什麼都不用做。N個矩形都處理過後,白紙集合中矩形就都是顏色為1的矩形,把它們的元素個數統計到顏色1中去即可。
其中矩形切割的函數是按著上面的虛擬碼寫的。
/*<br />ID: lingxiu1<br />LANG: C++<br />TASK: rect1<br />*/<br />#include<vector><br />#include<stdio.h><br />#include<string.h><br />#include<iostream><br />#include<algorithm><br />using namespace std;<br />struct RECT<br />{<br /> int x1, y1, x2, y2, col ; //x1,y1為左下角。x2,y2為右上方。col為顏色<br /> bool cut;//標記是否被切割<br />} ;</p><p>RECT rec[1001], temp; //rec儲存輸入的矩形 </p><p>vector<RECT> set; //set儲存被切出的白色矩形數集合</p><p>int cnt[2501] ; //cnt用來記錄每個顏色有多少個元素 </p><p>void count(int x1, int y1, int x2, int y2, int col)<br />{<br /> cnt[col] += (y2 - y1) * (x2 - x1) ; //記錄顏色為col的元素個數<br />}</p><p>void cut(int j, RECT b, int dir) //set[j]為白紙,若b與set[j]有交集則切割<br />{<br />if(set[j].y2 <= b.y1 || set[j].x1 >= b.x2 || set[j].x2 <= b.x1 || set[j].y1 >= b.y2 ) //沒有交集<br />return ; //直接返回<br />set[j].cut = 1 ; //標記被切割 </p><p> int k1, k2 ;<br /> if(dir == 1) //x方向(橫)<br /> {<br /> k1 = max(set[j].x1, b.x1) ;<br /> k2 = min(set[j].x2, b.x2) ; //k1, k2為x方向交集<br /> if(set[j].x1 < k1) {<br />temp.x1 = set[j].x1 ; temp.y1 = set[j].y1 ;<br />temp.x2 = k1 ; temp.y2 = set[j].y2 ;<br />temp.cut = 0 ;<br />set.push_back(temp) ; //切出白紙temp,加入集合<br />}<br /> if(k2 < set[j].x2) {<br />temp.x1 = k2 ; temp.y1 = set[j].y1 ;<br />temp.x2 = set[j].x2 ; temp.y2 = set[j].y2 ;<br />temp.cut = 0 ;<br />set.push_back(temp) ;//切出白紙temp,加入集合<br />}<br /> RECT c;<br /> c.x1 = k1 ; c.y1 = set[j].y1 ;<br /> c.x2 = k2 ; c.y2 = set[j].y2 ;<br /> set.push_back(c) ; //c為set[j]切掉x方向後的剩餘 </p><p> cut(set.size() - 1, b, dir + 1) ; //繼續y方向的切割<br /> }<br /> else //y方向 (豎)<br /> {<br /> k1 = max(set[j].y1, b.y1) ;<br /> k2 = min(set[j].y2, b.y2) ; //k1, k2為y方向交集<br /> if(set[j].y1 < k1) {<br />temp.x1 = set[j].x1 ; temp.y1 = set[j].y1 ;<br />temp.x2 = set[j].x2 ; temp.y2 = k1 ;<br />temp.cut = 0 ;<br />set.push_back(temp) ; //切出白紙temp,加入集合<br />}<br /> if(k2 < set[j].y2) {<br />temp.x1 = set[j].x1 ; temp.y1 = k2 ;<br />temp.x2 = set[j].x2 ; temp.y2 = set[j].y2 ;<br />temp.cut = 0 ;<br />set.push_back(temp) ; //切出白紙temp,加入集合<br />}<br /> count(max(b.x1, set[j].x1), k1, min(b.x2, set[j].x2), k2, b.col) ; //計算交集的元素個數,顏色為b的顏色<br />}<br />}<br />int main(){<br /> freopen("rect1.in","r",stdin);<br /> freopen("rect1.out","w",stdout);</p><p> int a, b, n, i, j, k ;<br /> scanf("%d%d%d", &a, &b, &n);<br /> for(i = 0; i < n; i ++)<br /> {<br /> scanf("%d%d%d%d%d", &rec[i].x1, &rec[i].y1, &rec[i].x2, &rec[i].y2, &rec[i].col);<br />}</p><p>memset(cnt, 0, sizeof(cnt)) ;<br />set.clear() ;</p><p>temp.x1 = 0 ; temp.y1 = 0 ;<br /> temp.x2 = a ; temp.y2 = b ;<br /> temp.cut = 0;<br /> set.push_back(temp) ; //第一張白紙 (0,0) (a,b) </p><p>for(i = n-1; i >= 0; i --)//倒序<br />{<br /> int tmp = set.size() ;<br /> for(j = 0; j < tmp; j ++)<br /> {<br /> cut(j, rec[i], 1); //每次覆蓋切出的白紙<br /> }<br /> for(vector<RECT>::iterator j = set.begin(); j != set.end(); )<br />if((*j).cut) { //被切過的白紙刪除<br />j = set.erase(j) ;<br />}<br />else j ++ ;<br /> }<br /> for(i = 0; i < set.size(); i ++)<br /> {<br /> count(set[i].x1, set[i].y1, set[i].x2, set[i].y2, 1);<br /> //最後計算所有白紙的個數<br /> }<br /> for(i = 1; i < 2501; i ++)<br /> {<br /> if(cnt[i]) printf("%d %d/n", i, cnt[i]);<br />}<br /> return 0;<br />}<br />
USER: li xiu [lingxiu1] TASK: rect1 LANG: C++
Compiling... Compile: OK Executing...
Test 1: TEST OK [0.000 secs, 3052 KB]
Test 2: TEST OK [0.000 secs, 3052 KB]
Test 3: TEST OK [0.000 secs, 3052 KB]
Test 4: TEST OK [0.000 secs, 3052 KB]
Test 5: TEST OK [0.000 secs, 3052 KB]
Test 6: TEST OK [0.000 secs, 3052 KB]
Test 7: TEST OK [0.000 secs, 3052 KB]
Test 8: TEST OK [0.000 secs, 3052 KB]
Test 9: TEST OK [0.000 secs, 3052 KB]
Test 10: TEST OK [0.000 secs, 3052 KB]
Test 11: TEST OK [0.011 secs, 3052 KB]
All tests OK.
Your program ('rect1') produced all correct answers! This is yoursubmission #12 for this problem.
Congratulations!
速度還不錯啊~