zoukankan      html  css  js  c++  java
  • 【XSY2693】景中人 区间DP

    题目描述

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

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

      问你最少要用几个矩形。

      (nleq 100,1leq yleq s)

    题解

      先把坐标离散化。

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

      考虑区间DP。

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

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

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

      对于每一个(h),这一层的转移是(O(n^3))的,到下一层的转移是(O(n^2log 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
    ",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;
    }
    
  • 相关阅读:
    在jenkins和sonar中集成jacoco(一)--使用jacoco收集单元测试的覆盖率
    持续集成一天一美元
    在jenkins和sonar中集成jacoco(二)--在jenkins中生成jacoco覆盖率报告
    day02--课后练习
    python之路-day02
    day01--课后练习
    python之路-day01
    python-FTP程序
    python-选课系统
    python- ATM与购物商城
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513582.html
Copyright © 2011-2022 走看看