【dp&技巧】书架 UVA12099

题意,n(<=70)本书,每本书有一个高度(<=150),宽度(<=30),把他们分到书架里的三层,每层的高度就是这层里所有书的最大高度,宽度就是所有书的宽度和。ans=三层高度和*三层宽度最大值,求ans最小值


又是一道ACM毒瘤好dp,最近做dp感觉出来了点规律,很多时候可以制定一些规则,使无论怎样都有最优答案都能满足这些规则,这样减少了最优答案的数量dp自然就简化了。所以在这个题中,如果求出来最优方案后,调整每一层的顺序不会改变答案,所以就定第一层高度最高,第二层其次。因为第一本书肯定要放进书架里,所以先把它放进第一层。


设状态的时候,设dp(i,j,k)为放了i本书,第二层宽度为j,第三层宽度为j,二三层高度和的最小值。这样根据j,k可以推出来第一层宽度。所以每次对于第i本书有放进三层三种决策,转移方程推一下就可以了。


这样会发现,如果把所有书放到一层,那么这一层宽度最大30*70=2100,空间用滚动数组优化,时间不优化是70*2100*2100,大数据会被卡(事实上vjudge上数据不强,最多20组测试数据跑了1180ms)

书上介绍了两个神仙优化,看完了以后我第一次知道dp还可以剪枝

1.这个还比较好想,放第i本书时j+k应小于第2本书到第i本书宽度和,这样可以在循环k时剪去一部分无用状态

2.所有书宽度和为sum,设想如果相邻两层宽度差>30,那么把一本书从这层拿到邻层,高度和不加,宽度也不加,所以我们只保留状态w1+30>=w2,w2+30>=w3,化式子可得w2<=(sum+30)/2,w3<=(sum+60)/3,这样w2最大1065,w3最大720常数小了六倍左右

这两个优化一上,常数小了六倍多,跑了180ms

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF (2100010)
#define LL long long
using namespace std;
int dp[2][1100][800],n,A[200];
struct Book{
	int w,h;
	void Read(){
		scanf("%d %d",&h,&w);
	}
	bool operator < (const Book &a) const{
		return h>a.h;
	}
}T[200];
LL Min(LL a,LL b){
	if (a<b) return a;
	return b;
}
void Work(){
	int i,j,k,sum=0,max2,max3;
	scanf("%d",&n);
	memset(A,0,sizeof(A));
	for (i=1;i<=n;i++) T[i].Read();
	sort(T+1,T+n+1);
	for (i=2;i<=n;i++) A[i]=T[i].w+A[i-1];
	sum=A[n]+T[1].w;
	
	memset(dp,127,sizeof(dp));
	max2=(sum+30)/2+10; max3=(sum+60)/3+10;
	dp[1][0][0]=0;
	for (i=2;i<=n;i++)
		for (j=0;j<=max2;j++)
			for (k=0;k+j<=A[i],k<=max3;k++){
				int &ans=dp[i&1][j][k];
				ans=INF;
				ans=min(ans,dp[(i-1)&1][j][k]);//把书放在第一层 
				if (j-T[i].w>=0)//把书放在第二层
					ans=min(ans,dp[(i-1)&1][j-T[i].w][k]+T[i].h*(j==T[i].w));
				if (k-T[i].w>=0)//把书放在第三层
					ans=min(ans,dp[(i-1)&1][j][k-T[i].w]+T[i].h*(k==T[i].w));
			}
	LL ans=210000000000000000;
	for (i=1;i<=max2;i++)
		for (j=1;j<=max3;j++)
			ans=Min(ans,(LL)max(max(i,j),sum-i-j)*(LL)(dp[n&1][i][j]+T[1].h));
	cout<<ans<<endl;			
}
int main(){
	int Case_Num;
	scanf("%d",&Case_Num);
	while (Case_Num--) Work();
	return 0;
}


猜你喜欢

转载自blog.csdn.net/lerbon23james/article/details/80070985
今日推荐