大致题意
用边平行于坐标轴的矩形来覆盖 n 个点,矩形至少要包含 2 个点(包括点位于边上的情况),矩形面积不能为 0 且顶点坐标都是整数。求覆盖全部点所用矩形的最小面积。2 ≤ n ≤ 15, −1,000 ≤ x, y ≤ 1,000
对覆盖的点进行状态压缩。首先确定搜索的子集,即矩形覆盖的点。求最小面积,矩形顶点至少有 2 个是需要覆盖的坐标点。遍历一遍 2 个点的组合,共 n * (n - 1) / 2 个,按位保存矩形覆盖的点,即可得到搜索的子集。
有部分矩形看起来是无用的,因为最小面积的求解中矩形一定是不相互覆盖的,也没有点是位于矩形顶点之外位置的。以上 2 种情况都可以找到更小的矩形面积,所以预处理时可以将这类矩形从遍历的对象中排除,以减小搜索次数。考虑最坏情况,即矩形 4 个顶点都覆盖了点,那么若某个矩形覆盖了超过 4 个以上的点,即可判断它不是最优解的可能搜索对象。对于题设矩形而言,边长一定大于等于 1 ,考虑边界情况,即 2 个顶点 x 或 y 轴坐标值相等,矩形退化成边,那么建立矩形对象的时候: ①求最小面积,即等于这条边的长度。因为某一边长度必须大于等于 1,可以用 max 方便地处理。②求覆盖点的子集。假设 2 个点坐标为 (x, y1), (x, y2),那么矩形第 3 个顶点可能的位置是 (x - 1, y1) 或 (x + 1, y1),有 2 种情况。实际上,只要对所有 x 轴坐标值相等的情况统一处理成 x + 1 或者 x - 1,即可覆盖所有最优解的可能子集。
状态转移 dp[s | sub] = min(dp[s | sub], dp[s] + area) ,dp[s] 即覆盖的点集合为 s 时矩形的最小面积。因为最优解的矩形间可能出现顶点相交(考虑 3 个点的情况就明白了),所以不能用 dp[s ^ sub] 转移状态。
#include <cstdio>
#include <STDLIB.H>
#include <algorithm>
#include <iostream>
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define abs(x) ((x) < 0 ? -(x) : (x))
#define INF 0x3f3f3f3f
#define eps 1e-4
#define M_PI 3.14159265358979323846
#define MAX_N 15
using namespace std;
struct rect{
int sub, area;
rect(int sub, int area) : sub(sub), area(area) {}
rect(){}
};
int N, M;
int X[MAX_N], Y[MAX_N];
rect R[MAX_N * (MAX_N - 1) / 2];
int dp[1 << MAX_N];
int calc(int i, int j){
return max(1, abs(X[i] - X[j])) * max(1, abs(Y[i] - Y[j]));
}
void init(){
for(int i = 0; i < N; i++) scanf("%d%d", X + i, Y + i);
M = 0;
for(int i = 0; i < N; i++){
for(int j = i + 1; j < N; j++){
int x1 = X[i], y1 = Y[i], x2 = X[j], y2 = Y[j];
if(x1 == x2) ++x1;
else if(y1 == y2) ++y1;
int cnt = 0, sub = 0;
for(int k = 0; k < N; k++){
if(((X[k] - x1) * (X[k] - x2) <= 0) && ((Y[k] - y1) * (Y[k] - y2) <= 0)){
++cnt, sub |= 1 << k;
}
}
if(cnt <= 4) R[M++] = rect(sub, calc(i, j));
}
}
}
void solve(){
memset(dp, 0x3f, sizeof(dp));
dp[0] = 0;
for(int i = 0; i < M; i++){
for(int s = 0; s < 1 << N; s++){
if(dp[s] != INF){
int nxt = s | R[i].sub;
if(nxt != s){
dp[nxt] = min(dp[nxt], dp[s] + R[i].area);
}
}
}
}
printf("%d\n", dp[(1 << N) - 1]);
}
int main(){
while(~scanf("%d", &N) && N){
init();
solve();
}
return 0;
}