码迷,mamicode.com
首页 > 其他好文 > 详细

【XSY2693】景中人 区间DP

时间:2018-03-06 12:52:05      阅读:239      评论:0      收藏:0      [点我收藏+]

标签:i++   mes   unique   记忆化搜索   复杂   down   while   mem   string   

题目描述

  平面上有\(n\)个点,你要用一些矩形覆盖这些点,要求:

  • 每个矩形的下边界为\(y=0\)
  • 每个矩形的大小不大于\(s\)

  问你最少要用几个矩形。

  \(n\leq 100,1\leq y\leq s\)

题解

  先把坐标离散化。

  猜(zheng)一个结论:最优解中任意两个矩形的横坐标只可能是相离或包含,不可能是相交。证明略。

  考虑区间DP。

  设\(f_{l,r,h}\)为覆盖横坐标\(l\sim r\),纵坐标\(>h\)的所有矩形需要的最少次数。

  枚举\(l,r,h\),有两种转移:

  • 找到一个横坐标\(i\),使得没有任意一个矩形穿过\(i\)。枚举\(i\)分治即可。
  • 放一个横坐标为\(l\sim r\)的矩形,把高度设为上限。

  对于每一个\(h\),这一层的转移是\(O(n^3)\)的,到下一层的转移是\(O(n^2\log n)\)的,所以总时间复杂度就是\(O(n^4)\)

  用记忆化搜索可以跑得飞快。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
using namespace std;
typedef pair<int,int> pii;
int n,s;
pii a[110];
int f[110][110][110];
int xx[110];
int yy[110];
int m1,m2;
int d[110];
int gao(int x)
{
    return x?s/x:0x3fffffff;
}
int gao(int l,int r,int h)
{
    int &s=f[h][l][r];
    if(~s)
        return s;
    while(l<=r&&d[l]<=h)
        l++;
    while(l<=r&&d[r]<=h)
        r--;
    if(l>r)
        return s=0;
    int i;
    s=0x7fffffff;
    for(i=l;i<r;i++)
        s=min(s,gao(l,i,h)+gao(i+1,r,h));
    int hh=gao(xx[r]-xx[l]);
    if(hh<=yy[h])
        return s;
    int v=upper_bound(yy+1,yy+m2+1,hh)-yy-1;
    s=min(s,gao(l,r,v)+1);
    return s; 
}
void solve()
{
    scanf("%d%d",&n,&s);
    int i;
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i].first,&a[i].second);
        xx[i]=a[i].first;
        yy[i]=a[i].second;
    }
    sort(xx+1,xx+n+1);
    sort(yy+1,yy+n+1);
    m1=unique(xx+1,xx+n+1)-xx-1;
    m2=unique(yy+1,yy+n+1)-yy-1;
    memset(f,-1,sizeof f);
    for(i=1;i<=m1;i++)
        d[i]=0;
    for(i=1;i<=n;i++)
    {
        a[i].first=lower_bound(xx+1,xx+m1+1,a[i].first)-xx;
        a[i].second=lower_bound(yy+1,yy+m2+1,a[i].second)-yy;
        d[a[i].first]=max(d[a[i].first],a[i].second);
    }
    int ans=gao(1,m1,0);
    printf("%d\n",ans);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    #endif
    int t;
    scanf("%d",&t);
    while(t--)
        solve();
    return 0;
}

【XSY2693】景中人 区间DP

标签:i++   mes   unique   记忆化搜索   复杂   down   while   mem   string   

原文地址:https://www.cnblogs.com/ywwyww/p/8513582.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!