Hdu5128 - The E-pang Palace
題意:給定n個點,要求從這n個點當中選擇8個點作為頂點來構成2個不相交(不能有任何一個點公共)的矩形,如果無法選出兩個這樣的矩形的話輸出imp,否則輸出這兩個矩形的最大的面積和。
分析:最容易想到的就是預處理出所有的矩形,假設有n個矩形,之后n*n跑一遍,但這樣可能達到C(30,4)*C(30,4)的復雜度,會超時。其實沒必要,類似于折半枚舉(雙向搜索)的思想,只要枚舉矩形的兩個對角點即兩個點就行了,然后判斷另外兩個點是否存在即可。所以枚舉量最多只有C(30,4)了。而且判斷兩個矩形是否相交的話我們不需要分類出所有的情況,從反面考慮,如果一個矩形在另一個矩形的上方或者左方或者下方或者右方的話就說明不相交了。而且另外一點是,對于一個矩形,我們只需要枚舉一次對角頂點的組合,另外一個組合沒必要枚舉,這樣減少了很多不必要的枚舉。而且對于選出的4個點,按照x從左從左至右排列假設為a,b,c,d四個點的話,只有3種組合方式(a,b)與(c,d),(a,c)與(b,d),(a,d)與(b,c),全部枚舉一下就好了。為方便判斷,可以事先給坐標排序,之后枚舉所有大小為4的子集,并且每次對3種組合方式判斷一下取最大值。
這題的一個坑點:一個矩形可能完全包含在另一個矩形中,這種情況下面積取較大者,否則取和。
暴力枚舉不失為一種好辦法,但是過多的枚舉必然會導致效率低下了。所以下手之前可以分析下,看是否可以減少重復的沒必要的枚舉,而且有時候減少這些枚舉還可以保證正確率,就像這題如果枚舉矩形的兩個對角的組合的話可能會導致判斷不全面導致計算錯誤,之前做的時候就是這樣,發現答案變大了,原因是因為考慮不全面,但是其實是沒必要的。而且折半枚舉也是一種重要的思想,因為很多情況下只需要枚舉一部分量,然后另一部分量直接判斷或者進行查找就好了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;struct po{int x, y;bool operator < (const po& a) const{return x == a.x ? y < a.y : x < a.x;}
}p[50];
int vis[210][210];int check(int i, int j, int k, int l)
{int ix = p[i].x, iy = p[i].y, jx = p[j].x, jy = p[j].y;int kx = p[k].x, ky = p[k].y, lx = p[l].x, ly = p[l].y;if (ix == jx || iy >= jy || kx == lx || ky >= ly) return 0;if (!vis[ix][jy] || !vis[jx][iy] || !vis[kx][ly] || !vis[lx][ky]) return 0;if (jx < kx || ix > lx || jy < ky || iy > ly) return (jx - ix) * (jy - iy) + (lx - kx) * (ly - ky);if (ix < kx && kx < jx && ix < lx && lx < jx && iy < ky && ky < jy && iy < ly && ly < jy) return (jx - ix) * (jy - iy);return 0;
}
int solve(int i, int j, int k, int l)
{return max(check(i, j, k, l), max(check(i, k, j, l), check(i, l, j, k)));
}
int main()
{int n;while (scanf("%d", &n), n){memset(vis, 0, sizeof(vis));for (int i = 0; i < n; i++) scanf("%d %d", &p[i].x, &p[i].y), vis[p[i].x][p[i].y] = 1;if (n < 8) { puts("imp"); continue; }sort(p, p + n);int k = (1 << 4) - 1;int ans = 0;while (k < 1 << n){int t[4];for (int i = 0, j = 0; i < n; i++)if (k & (1 << i)) t[j++] = i;ans = max(ans, solve(t[0], t[1], t[2], t[3]));int x = k & -k, y = k + x;k = ((k & ~y) / x >> 1) | y;}ans ? printf("%d\n", ans) : puts("imp");}return 0;
}
總結
以上是生活随笔為你收集整理的Hdu5128 - The E-pang Palac的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。