铺地板:坐标平面上有n各点,用任意大小(非零)的地板砖覆盖它们,求最省的地板砖总面积。
地板即矩形,平行于坐标轴,且必包含两个点,n<=15
可以枚举任意2个点作为对顶角点的矩形面积,并算出含多点,(状压到一个int)
可知道这些矩形必包含所有最优矩形。
遍历所有矩形,用每一个去更新所有状态
state=0:1<<n
根据dp[新矩形集合] = min(dp[新矩形集合], dp[旧矩形集合] + 新矩形的面积);
dp[s]表示矩形集合为s时,覆盖点情况为s的二进制情况,的最小面积
复杂度
n*n*(2^n)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const double pi=acos(-1.0);
double eps=0.000001;
typedef long long ll;
const int N=20;
const int inf=1e9;
int dp[1<<16];
struct rec
{
int cover;
int area;
rec() {}
rec(int a,int b)
{
cover=a,area=b;
}
void add(int x)
{
cover|=1<<x;
}
};
int xx[N],yy[N];
bool check(int i,int j,int k) // 因为k夹在i,j之间,且矩形与x轴平行
{
return
( (xx[i]-xx[k])*(xx[j]-xx[k])<=0) &&
( (yy[i]-yy[k])*(yy[j]-yy[k])<=0) ;
}
vector<rec > tt;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
if (!n)break;
for (int i=0; i<n; i++)
scanf("%d%d",&xx[i],&yy[i]);
tt.clear();
for (int i=0; i<n; i++)
for (int j=i+1; j<n; j++)
{
rec tmp((1<<i)|(1<<j),max(1,abs(xx[i]-xx[j])) *max(1,abs(yy[i]-yy[j])) );
for (int k=0; k<n; k++)
{
if (check(i,j,k))
tmp.add(k);
}
tt.push_back(tmp);
}
int all=1<<n;
for (int i=1; i<all; i++) dp[i]=inf;
dp[0]=0;
for (int i=0; i<tt.size(); i++)
{
rec tmp=tt[i];
for (int j=0; j<all; j++)
{
int nex=j|tmp.cover;
if (dp[j]!=inf && j!=nex)
dp[nex]=min(dp[nex],dp[j]+tmp.area);
}
}
printf("%d\n",dp[all-1]);
}
return 0;
}
本文介绍了一种通过枚举矩形来寻找覆盖平面上多个点的最省地板砖总面积的方法。利用状态压缩技术,该算法能在合理的计算时间内找到最优解。
2367

被折叠的 条评论
为什么被折叠?



