POJ-2836-Rectangular Covering

378 篇文章 0 订阅

这个题求的用最小的矩形面积把所有的点覆盖,需要注意的是这里的覆盖指的是这些点必须在矩形的边上,然后矩形每次至少要覆盖2个点。需要注意的是共线的时候需要把宽度调整为1,然后剩下的用dp可以解决。DP[i[表示在状态i的时候至少需要多少的面积,i为状态压缩值,把当前已经覆盖的点的状态记录下来。还有一点是2个点构成的矩形要面积最小,那么这2个点一定在角上,所以面积就比较好算了。

        这个题我最开始打算枚举状态,然后枚举操作,结果果断TLE。后来直接先预处理所有可能的操作,然后再枚举,就AC了~

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=1<<29;
const int maxn=1<<15;
const int maxm=20;
struct Node
{
    int val;
    int pos;
    Node(){}
    Node(int sval,int spos):val(sval),pos(spos){}
}s[300];
int n,dp[maxn],x[maxm],y[maxm],cnt;
int Abs(int x)
{
    return x>0?x:-x;
}
void Init()
{
    for(int i=0;i<maxn;i++)
        dp[i]=inf;
    dp[0]=0;
}
bool Onborder(int i,int j,int k)
{
    if((x[k]==x[i]||x[k]==x[j])&&y[k]<=max(y[i],y[j])&&y[k]>=min(y[i],y[j]))
        return true;
    if((y[k]==y[i]||y[k]==y[j])&&x[k]<=max(x[i],x[j])&&x[k]>=min(x[i],x[j]))
        return true;
    return false;
}
int Area(int i,int j,int &pos)
{
    pos|=1<<i;
    pos|=1<<j;
    for(int k=0;k<n;k++)
        if(Onborder(i,j,k))
            pos|=1<<k;
    if(x[i]==x[j]||y[i]==y[j])
        return max(Abs(x[i]-x[j]),Abs(y[i]-y[j]));
    return Abs(x[i]-x[j])*Abs(y[i]-y[j]);
}
int main()
{
    while(scanf("%d",&n)&&n)
    {
        cnt=0;
        Init();
        for(int i=0;i<n;i++)
            scanf("%d%d",&x[i],&y[i]);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(i!=j)
                {
                    int pos=0;
                    int val=Area(i,j,pos);
                    s[cnt++]=Node(val,pos);
                }
        for(int i=0;i<maxn;i++)
            for(int j=0;j<cnt;j++)
                dp[i|s[j].pos]=min(dp[i|s[j].pos],dp[i]+s[j].val);
        printf("%d\n",dp[(1<<n)-1]);

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值