UVALive 3637 The Bookcase(DP)

本文介绍了一种使用动态规划解决书架摆放问题的方法,通过预处理书的高度并按从高到低排序,实现O(n(sum(t)^2))的时间复杂度。文中详细解释了状态转移方程和边界条件,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

用O(n(sum(t)^2))的方法过的心惊胆战。。1800+ms惊险AC。。幸好AC了要是TLE了还得打回去重想。。

思路是直接枚举各层宽度,由于书的总宽度固定所有只需要记录下面两层的宽度即可。

设dp[k][i][j]为当前书架放了前k本书,第一层宽度为i,第二层宽度为j时的最低高度。

为了避免不断去比较高度,先将所有书按从高到低排序,那么只需在空的层中放入书时需要加上书的高度之外,每次放入新的书都无需再更新高度(因为下一本书必定比同层的书高度低,故不会影响到该层的最高高度)。

状态转移也很好想,每本书只有放第一层、放第二层、放第三层这三种决策,去找对应的状态就行了。

需要注意最终状态不允许有哪层是空的。

感觉这种方法还是有点拼rp的,不知道有没有更优的方法。

代码如下:

#include<bits/stdc++.h>
#define INF 1000000000
using namespace std;

struct node
{
	int h,w;
	bool operator <(const node &p)const
	{
		return h>p.h;
	}
};

node a[105];

int dp[2][2105][2105];

int n;

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		int SW=0;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&a[i].h,&a[i].w);
			SW+=a[i].w;
		}
		sort(a,a+n);
		for(int i=0;i<=SW;i++)
			for(int j=0;j<=SW;j++)
				dp[0][i][j]=INF;
		dp[0][0][0]=0;
		int cur=1;
		int SumW=0;
		for(int k=0;k<n;k++)
		{
			SumW+=a[k].w;
			for(int i=0;i<=SW;i++)
				for(int j=0;j<=SW;j++)
				{
					dp[cur][i][j]=INF;
					int p=j-a[k].w;
					if(p==0)
						dp[cur][i][j]=min(dp[cur][i][j],dp[cur^1][i][p]+a[k].h);
					else if(p>0)
						dp[cur][i][j]=min(dp[cur][i][j],dp[cur^1][i][p]);
					p=i-a[k].w;
					if(p==0)
						dp[cur][i][j]=min(dp[cur][i][j],dp[cur^1][p][j]+a[k].h);
					else if(p>0)
						dp[cur][i][j]=min(dp[cur][i][j],dp[cur^1][p][j]);
					p=SumW-i-j-a[k].w;
					if(p==0)
						dp[cur][i][j]=min(dp[cur][i][j],dp[cur^1][i][j]+a[k].h);
					else if(p>0)
						dp[cur][i][j]=min(dp[cur][i][j],dp[cur^1][i][j]);
//					if(dp[cur][i][j]!=INF)printf("dp[%d][%d][%d]=%d\n",k,i,j,dp[cur][i][j]);
				}
			cur^=1;
		}
		cur^=1;
		int ans=INF;
		for(int i=1;i<=SW;i++)
			for(int j=1;j<=SW;j++)
			{
				if(dp[cur][i][j]>=INF)continue;
				if(SumW-i-j==0)continue;
				int W=max(max(i,j),SumW-i-j);
				ans=min(ans,dp[cur][i][j]*W);
			}
		printf("%d\n",ans);
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值