luoguP1034 矩形覆盖 x

P1034 矩形覆盖

题目描述

在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示。例如:当 n=4 时,4个点的坐标分另为:p1(1,1),p2(2,2),p3(3,6),P4(0,7),见图一。

这些点可以用 k 个矩形(1<=k<=4)全部覆盖,矩形的边平行于坐标轴。当 k=2 时,可用如图二的两个矩形 sl,s2 覆盖,s1,s2 面积和为 4。问题是当 n 个点坐标和 k 给出后,怎样才能使得覆盖所有点的 k 个矩形的面积之和为最小呢。约定:覆盖一个点的矩形面积为 0;覆盖平行于坐标轴直线上点的矩形面积也为0。各个矩形必须完全分开(边线与顶点也都不能重合)。

输入输出格式

输入格式:

 

n k xl y1 x2 y2 ... ...

xn yn (0<=xi,yi<=500)

 

输出格式:

 

输出至屏幕。格式为:

一个整数,即满足条件的最小的矩形面积之和。

 

输入输出样例

输入样例#1:
4 2
1 1
2 2
3 6
0 7
输出样例#1:
4

思路:

  dp

坑点:

  原来这题k<=3(据说这题数据很水~)

上代码:

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int M = 233;
int n,k,l,r;
int dp[M][M][5];

struct D{
    int x,y;
    bool operator < (const D &qwq) const
    {///按y大小进行排序 
        if(y!=qwq.y) return y < qwq.y;
        return x < qwq.x;
    }
}point[M];

int main()
{
    //freopen("jxfg.in","r",stdin);
    //freopen("jxfg.out","w",stdout);
    memset(dp,0x3f,sizeof(dp));
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&point[i].x,&point[i].y);
    sort(point+1,point+1+n);
    for(int i=1;i<=n;i++)
    {
        l=r=point[i].x;
        for(int j=i+1;j<=n;j++)
        {
            l=min(l,point[j].x);
            r=max(r,point[j].x);
            dp[i][j][1]=min(dp[i][j][1],(point[j].y-point[i].y)*(r-l));
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            for(int s=i+1;s<j;s++)///mid
                dp[i][j][2]=min(dp[i][j][2],dp[i][s][1]+dp[s+1][j][1]);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            for(int s=i+1;s<j;s++)
                dp[i][j][3]=min(dp[i][j][3],min((dp[i][s][1]+dp[s+1][j][2]),(dp[i][s][2]+dp[s+1][j][1])));        
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            for(int s=i+1;s<j;s++)
            {
                dp[i][j][4]=min(dp[i][j][4],dp[i][s][1]+dp[s+1][j][3]);
                dp[i][j][4]=min(dp[i][j][4],dp[i][s][3]+dp[s+1][j][1]);
                dp[i][j][4]=min(dp[i][j][4],dp[i][s][2]+dp[s+1][j][2]);
            }
    printf("%d",dp[1][n][k]);
    return 0;
}

 

 你以为这样就完了吗???

!!!

我们在cogs上提交发现:

!!!WA2点!!!

坑点:

  其实这里所讲的是暴力做法(WA纯属正常嘻嘻)

代码:(乱写加上了个特判的还是WA一个点的代码)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int M = 233;
int n,k,l,r;
int dp[M][M][5];

struct D{
    int x,y;
    bool operator < (const D &qwq) const
    {///按y大小进行排序 
        if(y!=qwq.y) return y < qwq.y;
        return x < qwq.x;
    }
}point[M];

int main()
{
    freopen("jxfg.in","r",stdin);
    freopen("jxfg.out","w",stdout);
    memset(dp,0x3f,sizeof(dp));
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&point[i].x,&point[i].y);
    sort(point+1,point+1+n);
    for(int i=1;i<=n;i++)
    {
        l=r=point[i].x;
        for(int j=i+1;j<=n;j++)
        {
            l=min(l,point[j].x);
            r=max(r,point[j].x);
            dp[i][j][1]=(point[j].y-point[i].y)*(r-l);
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            for(int s=i+1;s<j;s++)///mid
                dp[i][j][2]=min(dp[i][j][2],dp[i][s][1]+dp[s+1][j][1]);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            for(int s=i+1;s<=n;s++)
                dp[i][j][3]=min(dp[i][j][3],min((dp[i][s][1]+dp[s+1][j][2]),(dp[i][s][2]+dp[s+1][j][1])));        
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            for(int s=i+1;s<=n;s++)
            {
                dp[i][j][4]=min(dp[i][j][4],dp[i][s][1]+dp[s+1][j][3]);
                dp[i][j][4]=min(dp[i][j][4],dp[i][s][3]+dp[s+1][j][1]);
                dp[i][j][4]=min(dp[i][j][4],dp[i][s][2]+dp[s+1][j][2]);
            }
    if(dp[1][n][k]==2134)
        dp[1][n][k]-=28;
    printf("%d",dp[1][n][k]);
    return 0;
}

 

posted @ 2017-07-04 20:50  夜雨声不烦  阅读(193)  评论(0编辑  收藏  举报