【NOIP2002提高组T4】矩形覆盖-DFS剪枝
(本人本题完成于2016-7-21)
题目大意:用K(不超过4)个矩形覆盖平面上的N(不超过50)个点,求这些矩形面积之和的最小值。
做法:记录每一个矩形的左下角和右上角坐标,左下角坐标初始化为(inf,inf),右上角坐标初始化为(-inf,-inf)。然后DFS,枚举当前的点在哪一个矩形中,如果当前的点不在枚举到的矩形中,则相应的将矩形扩大到正好覆盖这个点,如果此时矩形之间没有相互覆盖并且矩形的总面积没有超过当前已得的最优解,则继续拓展。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define inf 99999999
using namespace std;
int n,k,ans=inf;
struct dot
{
int x,y;
}d[51];
struct sqr
{
dot l,r;
}rec[5];
bool conf(int i,int j)
{
if (rec[i].l.x==inf||rec[i].l.y==inf||rec[i].r.x==-inf||rec[i].r.y==-inf)
return 0;
if (rec[j].l.x==inf||rec[j].l.y==inf||rec[j].r.x==-inf||rec[j].r.y==-inf)
return 0;
if (rec[i].l.x>rec[j].r.x||rec[i].l.y>rec[j].r.y) return 0;
if (rec[j].l.x>rec[i].r.x||rec[j].l.y>rec[i].r.y) return 0;
return 1;
} //判断矩形i,j是否相互覆盖
bool can()
{
for(int i=1;i<=k;i++)
for(int j=i+1;j<=k;j++)
if (conf(i,j)) return 0;
return 1;
} //判断矩形间是否相互覆盖
int getS()
{
int S=0;
for(int i=1;i<=k;i++)
if (rec[i].l.x!=inf) //如果这个矩形还在初始状态,不计算其面积(因为这表示还没有在这个矩形中加入点)
S+=(rec[i].r.x-rec[i].l.x)*(rec[i].r.y-rec[i].l.y);
return S;
} //获取当前矩形的总面积
void dfs(int used)
{
if (used==n) //已经加入了n个点,结束搜索
{
int S=getS();
if (S<ans) ans=S;
return;
}
for(int i=1;i<=k;i++)
{
sqr temp=rec[i];
if (rec[i].l.x>d[used+1].x) rec[i].l.x=d[used+1].x;
if (rec[i].l.y>d[used+1].y) rec[i].l.y=d[used+1].y;
if (rec[i].r.x<d[used+1].x) rec[i].r.x=d[used+1].x;
if (rec[i].r.y<d[used+1].y) rec[i].r.y=d[used+1].y;
if (can()&&getS()<ans) dfs(used+1); //剪枝
rec[i]=temp;
}
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d %d",&d[i].x,&d[i].y);
for(int i=1;i<=k;i++)
{
rec[i].l.x=rec[i].l.y=inf;
rec[i].r.x=rec[i].r.y=-inf;
}
dfs(0); //DFS
printf("%d",ans);
return 0;
}