景中人 - dp

题目大意:平面上第一象限给你一些点,你要用尽可能少的面积不超过S的矩形,使得每个矩形的底边紧贴x轴,并且矩形的并覆盖所有点。 n 100 n\le100 .
题解:
性质:存在一种最优解,矩形的底边存在包含关系或者相离。
因此考虑一个区间dp,设dp[i,j,k]表示i到j的点覆盖k高度及以上的点的最小代价,转移枚举分两半或者选[i,j]即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=110;
vector<int> vx,vy;int x[N],y[N],dp[N][N][N],yp[N];
inline int getid(int x,vector<int> &v) { return lower_bound(v.begin(),v.end(),x)-v.begin()+1; }
int main()
{
//  freopen("data.in","r",stdin),freopen("std.out","w",stdout);
    for(int T=inn();T;T--)
    {
        int n=inn(),S=inn(),t;vx.clear(),vy.clear();
        rep(i,1,n) vx.pb(x[i]=inn()),vy.pb(y[i]=inn());
        sort(vx.begin(),vx.end()),vx.erase(unique(vx.begin(),vx.end()),vx.end());
        sort(vy.begin(),vy.end()),vy.erase(unique(vy.begin(),vy.end()),vy.end());
        int m=(int)vy.size();memset(yp,0,sizeof(int)*((int)vx.size()+1));
        rep(i,1,n) t=getid(x[i],vx),yp[t]=max(yp[t],getid(y[i],vy));
        n=(int)vx.size(),memcpy(y,yp,sizeof(int)*(n+1));
        rep(i,1,n) rep(j,1,m) dp[i][i][j]=(j<=y[i]);
        rep(i,1,n) rep(j,i,n) dp[i][j][m+1]=dp[i][j][m+2]=0;
        rep(len,2,n) rep(i,1,n-len+1) for(int k=m;k;k--)
        {
            int j=i+len-1;dp[i][j][k]=j-i+1;
            rep(t,i,j-1) dp[i][j][k]=min(dp[i][j][k],dp[i][t][k]+dp[t+1][j][k]);
            int ymx=getid(S/(vx[j-1]-vx[i-1]),vy);
            if(S/(vx[j-1]-vx[i-1])<vy[ymx-1]) ymx--;
            if(ymx<max(max(y[i],y[j]),k)) continue;
            dp[i][j][k]=min(dp[i][j][k],dp[i][j][ymx+1]+1);
        }
        printf("%d\n",dp[1][n][1]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/84537802
DP
DP?