题目大意:在一个平面里,有n个点,用若干矩形来覆盖所有点,每个矩形的所有边上都必须包含一共至少两个点,求最小总面积。
分析:状压DP。状态:dp[i]表示点集为i时的最小面积。
状态转移方程:dp[新点集] = min(dp[新点集] , dp[旧点集]+新矩形面积)
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
struct Rect {
int area;
int pset;
}rect[300];
int dp[1<<16];
int x[20], y[20];
int n;
int main() {
while(scanf("%d", &n) && n) {
for(int i = 0; i < n; i++)
scanf("%d%d", &x[i], &y[i]);
int cnt = 0;
for(int i = 0; i < n-1; i++) {
for(int j = i+1; j < n; j++) {
rect[cnt].area = max(1, abs(x[i]-x[j]))*max(1, abs(y[i]-y[j]));
rect[cnt].pset = (1<<i) | (1<<j);
for(int k = 0; k < n; k++) {
if((x[i]-x[k])*(x[j]-x[k]) <= 0 && (y[i]-y[k])*(y[j]-y[k]) <= 0)
rect[cnt].pset |= 1<<k;
}
cnt++;
}
}
fill(dp, dp+(1<<16), 1<<30);
dp[0] = 0;
for(int i = 0; i < cnt; i++) {
for(int j = 0; j < 1<<n; j++) {
int p = j|rect[i].pset;
if(dp[j] != 1<<30 && p != j) {
dp[p] = min(dp[p], dp[j]+rect[i].area);
}
}
}
printf("%d\n", dp[(1<<n)-1]);
}
return 0;
}