1. 程式人生 > >題解 P1034 【矩形覆蓋】

題解 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時,可用如圖二的兩個矩形S1,s2覆蓋,81,S2面積和為4。問題是當n個點座標和k給出後,怎樣才能使得覆蓋所有點的k個矩形的面積之和為最小呢?
約定:覆蓋一個點的矩形面積為0;覆蓋平行於座標軸直線上點的矩形面積也為0。各個矩形必須完全分開(邊線與頂點也都不能重合)。

題意

有n個點,找k個矩形包含所有點,使k個矩形和麵積和最小。

題解

這道題剛拿到手裡的時候是挺棘手的,但是我們看資料範圍的大小,是可以暴力列舉的,所以我們可以嘗試一下暴力列舉。

建圖操作

  1. maps用來存圖

  2. ss用來存構建的矩形

    • 立flag來統計這種矩形是否建過

    • 資料最大是4塊矩形,可以開小陣列

struct maps
{
    int x,y;
} mapp[51];
struct ss
{
    int l,r,u,d;
    bool flag;
} p[5];

判斷操作

  1. judge函式列舉四種不成立的情況

  2. in函式判斷範圍,便於書寫judge函式

bool in(ss a, int x, int y)
{
    if (x>=a.l&&x<=a.r&&y>=a.d&&y<=a.u) return 1;
    return 0;
}

bool judge(ss a, ss b)
{
    if (in(a,b.l,b.u)) return 1;
    if (in(a,b.l,b.d)) return 1;
    if (in(a,b.r,b.u)) return 1;
    if (in(a,b.r,b.d)) return 1;
    return 0;
}

dfs操作

  1. 構建好m個矩形

  2. 計算面積和

  3. 每次存最小值

  4. 搜完結束

void dfs(int num)
{
    int value=0;
    for (int i=1; i<=m; i++)
    {
      if (p[i].flag)
      {
        for (int j=i+1; j<=m; j++)
          if (judge(p[i],p[j])) return;
      }
      value+=(p[i].r-p[i].l)*(p[i].u-p[i].d);
    }

    if (value>=ans) return;

    if (num>n){
        ans=value;
        return;
    }

    for (int i=1; i<=m; i++)
    {
        ss tmp=p[i];
        if (p[i].flag==0)
        {
            p[i].flag=1;
            p[i].l=p[i].r=mapp[num].x;
            p[i].u=p[i].d=mapp[num].y;
            dfs(num+1); p[i]=tmp;
            break;
        }
        else 
        {
            p[i].r=max(p[i].r,mapp[num].x);             
            p[i].l=min(p[i].l,mapp[num].x);
            p[i].u=max(p[i].u,mapp[num].y); 
            p[i].d=min(p[i].d,mapp[num].y);
            dfs(num+1);
            p[i]=tmp;
        }    
    }
}

程式碼

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

struct maps
{
    int x,y;
} mapp[51];
struct ss
{
    int l,r,u,d;
    bool flag;
} p[5];

int n,m,ans=0x7f7f7f7f;

bool in(ss a, int x, int y)
{
    if (x>=a.l&&x<=a.r&&y>=a.d&&y<=a.u) return 1;
    return 0;
}

bool judge(ss a, ss b)
{
    if (in(a,b.l,b.u)) return 1;
    if (in(a,b.l,b.d)) return 1;
    if (in(a,b.r,b.u)) return 1;
    if (in(a,b.r,b.d)) return 1;
    return 0;
}

void dfs(int num)
{
    int value=0;
    for (int i=1; i<=m; i++)
    {
      if (p[i].flag)
      {
        for (int j=i+1; j<=m; j++)
          if (judge(p[i],p[j])) return;
      }
      value+=(p[i].r-p[i].l)*(p[i].u-p[i].d);
    }

    if (value>=ans) return;

    if (num>n){
        ans=value;
        return;
    }

    for (int i=1; i<=m; i++)
    {
        ss tmp=p[i];
        if (p[i].flag==0)
        {
            p[i].flag=1;
            p[i].l=p[i].r=mapp[num].x;
            p[i].u=p[i].d=mapp[num].y;
            dfs(num+1); p[i]=tmp;
            break;
        }
        else 
        {
            p[i].r=max(p[i].r,mapp[num].x); 
            p[i].l=min(p[i].l,mapp[num].x);
            p[i].u=max(p[i].u,mapp[num].y); 
            p[i].d=min(p[i].d,mapp[num].y);
            dfs(num+1);
            p[i]=tmp;
        }    
    }
}

int main(void)
{
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++) scanf("%d%d",&mapp[i].x,&mapp[i].y);

    dfs(1);
    printf("%d",ans);

    return 0;
}