zoukankan      html  css  js  c++  java
  • 【SHOI2007】书柜的尺寸

    dp

    如果我们直接定义状态:

    (dp[i][t1][t2][t3][h1][h2][h3])表示前i个,第一层宽度为t1,,第二层宽度为t2,第三层宽度为t3,第一层高度为h1,第二层高度为h2,第三层高度为h3的最小面积。

    如果直接这样定义,你会发现,你不仅内存炸飞,时间也会T的飞起。

    考虑优化状态。

    1.首先,你会发现,面积可以直接用t1,t2,t3,h1,h2,h3算出来,所以我们不妨砍掉一维

    2.列一波状态转移方程,你会发现,i只会从i-1转移过来,于是又可以把第一维滚动

    3.不难发现,(t1+t2+t3=sum _{j=1}^{j le i} t_j)于是只用知道t1,t2,t3中的任意两个,就可以推出第三个

    那么,状态就优化成了:(dp[0/1][t1][t2][h1][h2])表示前i个,第一层宽度为t1,,第二层宽度为t2,第一层高度为h1,第二层高度为h2,的第三层最小高度。

    然后,你又会发现,内存和时间依旧承受不住。。。

    仔细琢磨一下,不难观察到,每一层的高度是这一层中所放书本的最大值,那么如果按照一定顺序插入书本,高度不就可以省略掉了吗?

    因此,我们先把书本按高度从大到小排个序,这样每层的高度就是第一次插入到这层书的高度,于是状态又优化成了:(dp[0/1][t1][t2])表示前i个,第一层宽度为t1,第二层宽度为t2,的最小三层总高度

    转移的话就不用多说了吧。。。

    代码:

    注意一点,每层至少得有1本书,因此最后算面积时要排除某一层没有书的情况。(第二组样例已经良心地说明了这点)

    #include<bits/stdc++.h>
    using namespace std;
    int n,dp[2][2110][2110],sum[101],ans=(1<<30);
    struct node{
    	int t,h;
    }A[1010];
    bool cmp(node A,node B){
    	return A.h>B.h;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)scanf("%d %d",&A[i].h,&A[i].t);
    	memset(dp,63,sizeof(dp));
    	const int oo=dp[0][0][0];
    	sort(A+1,A+1+n,cmp);
    	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+A[i].t;
    	dp[0][0][0]=0;
    	for(int i=1;i<=n;i++){
    		int now=i&1,la=!now;
    		memset(dp[now],63,sizeof(dp[now]));
    		for(int j=0;j<=sum[i-1];j++){
    			for(int k=0;k<=sum[i-1];k++){
    				int o=sum[i-1]-j-k;
    				if(o<0)continue;
    				if(dp[la][j][k]==oo)continue;
    				if(j==0)dp[now][j+A[i].t][k]=min(dp[now][j+A[i].t][k],dp[la][j][k]+A[i].h);
    				else dp[now][j+A[i].t][k]=min(dp[now][j+A[i].t][k],dp[la][j][k]);
    				if(k==0)dp[now][j][k+A[i].t]=min(dp[now][j][k+A[i].t],dp[la][j][k]+A[i].h);
    				else dp[now][j][k+A[i].t]=min(dp[now][j][k+A[i].t],dp[la][j][k]);
    				if(o==0)dp[now][j][k]=min(dp[now][j][k],dp[la][j][k]+A[i].h);
    				else dp[now][j][k]=min(dp[now][j][k],dp[la][j][k]);
    			}
    		}
    	}
    	for(int i=1;i<=sum[n];i++){
    		for(int j=1;j<=sum[n];j++){
    			int o=sum[n]-i-j;
    			if(o<=0)continue;
    			if(dp[n&1][i][j]==oo)continue;
    			ans=min(ans,max(max(i,j),o)*dp[n&1][i][j]);
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    _ 下划线 Underscores __init__
    Page not found (404) 不被Django的exception中间件捕捉 中间件
    从装修儿童房时的门锁说起
    欧拉定理 费马小定理的推广
    线性运算 非线性运算
    Optimistic concurrency control 死锁 悲观锁 乐观锁 自旋锁
    Avoiding Full Table Scans
    批量的单向的ssh 认证
    批量的单向的ssh 认证
    Corrupted MAC on input at /usr/local/perl/lib/site_perl/5.22.1/x86_64-linux/Net/SSH/Perl/Packet.pm l
  • 原文地址:https://www.cnblogs.com/SillyTieT/p/11415298.html
Copyright © 2011-2022 走看看