Rectangular Covering POJ - 2836
考察:状压dp
本蒟蒻是完全没思路...基本照抄大佬代码
照搬大佬的思路:
首先要知道包围两个点的最小矩形面积是两个点刚好在矩形的对角线上.根据这个我们构造n*(n-1)/2个矩形.对于每个点我们检查矩阵是否将它包含在内部,如果包含就记录下来.这样每个矩形都有它包含的点集.根据这个dp方程是f[i] = f[k]+v[j].area 其中i是点的集合.因为不是所有构造的矩形都是需要的,所以可以优化到一维,如果用二维初始化需要将每个矩形的点集在dp数组里初始化.
注意:重复的面积也要计入
再再注意:边长最短为1
还有一个比较关键的点是在一条线上的点,按思维我们会像将宽往哪边扩1会更优.这里有几种情况:
1.有其他点在线上,此时哪边都行
2.有点在线上(下左右)方,可以发现往点在的方向扩宽的面积刚好等于该点与线上点的面积和.
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 const int N = 16,INF = 0x3f3f3f3f; 8 struct Block{ 9 int area; 10 int points; 11 }block; 12 typedef pair<int,int> PII; 13 PII p[N]; 14 int n,f[1<<N],all; 15 vector<Block> v; 16 int calc(PII x,PII y) 17 { 18 int l = max(abs(x.first-y.first),1); 19 int w = max(abs(x.second-y.second),1); 20 return l*w; 21 } 22 bool check(PII x,PII y,PII z) 23 { 24 int mins = min(x.first,y.first),maxn = max(x.first,y.first); 25 if(z.first>=mins&&z.first<=maxn) 26 { 27 mins = min(x.second,y.second),maxn = max(y.second,x.second); 28 if(z.second>=mins&&z.second<=maxn) return true; 29 return false; 30 } 31 return false; 32 } 33 void inits() 34 { 35 Block tmp; 36 v.clear(); all = (1<<n)-1; 37 v.push_back(tmp); 38 for(int i=1;i<n;i++) 39 for(int j=i+1;j<=n;j++) 40 { 41 Block t; 42 t.area = calc(p[i],p[j]); t.points = (1<<(i-1))|(1<<(j-1)); 43 for(int k=1;k<=n;k++) 44 if(k!=i&&k!=j) if(check(p[i],p[j],p[k])) t.points|=(1<<(k-1)); 45 v.push_back(t); 46 } 47 } 48 int main() 49 { 50 while(scanf("%d",&n)!=EOF&&n) 51 { 52 memset(f,0x3f,sizeof f); 53 f[0] = 0; 54 for(int i=1;i<=n;i++) scanf("%d%d",&p[i].first,&p[i].second); 55 inits(); 56 for(int i=0;i<1<<n;i++) 57 for(int j=1;j<v.size();j++) 58 f[i|v[j].points] = min(f[i]+v[j].area,f[i|v[j].points]); 59 printf("%d\n",f[all]); 60 } 61 return 0; 62 }