解题思考(DP问题)C. 搬寝室

题目描述

Problem Description
搬寝室是很累的,xhd深有体会.时间追述2006年7月9号,那天xhd迫于无奈要从27号楼搬到3号楼,因为10号要封楼了.看着寝室里的n件物品,xhd开始发呆,因为n是一个小于2000的整数,实在是太多了,于是xhd决定随便搬2k件过去就行了.但还是会很累,因为2k也不小是一个不大于n的整数.幸运的是xhd根据多年的搬东西的经验发现每搬一次的疲劳度是和左右手的物品的重量差的平方成正比(这里补充一句,xhd每次搬两件东西,左手一件右手一件).例如xhd左手拿重量为3的物品,右手拿重量为6的物品,则他搬完这次的疲劳度为(6-3)^2 = 9.现在可怜的xhd希望知道搬完这2*k件物品后的最佳状态是怎样的(也就是最低的疲劳度),请告诉他吧.

Input
每组输入数据有两行,第一行有两个数n,k(2<=2*k<=n<2000).第二行有n个整数分别表示n件物品的重量(重量是一个小于2^15的正整数).

Output
对应每组输入数据,输出数据只有一个表示他的最少的疲劳度,每个一行.

输入样例

2 1
1 3

输出样例

4

思考:此DP算法用到递推思考的方式,代码书写又类似于数塔问题。

首先要对所有物品按找质量进行排序,因为搬运质量相邻物品才能做到最少消耗。

要求n个物品搬m趟,不妨从2个物品搬1趟(选1对)开始,

随后3个物品选1对:要么前两个物品选一对,要么后两个物品选1对;

4个物品选1对:运用到前面算出来的3个物品选1对所得到的结果,比较要么是前3个物品选一对,要么是第3个和第4个物品选一对

4个物品选2对:1,2和3,4分别组对。

部分代码如下:

for(j=2; j<=n; j++)//物品数 
            for(i=1; i*2<=j; i++)//次数 
				cost[j][i]=mini(cost[j-1][i],cost[j-2][i-1]+(arr[j]-arr[j-1])*(arr[j]-arr[j-1]));

整体代码如下:

#include<bits/stdc++.h>
using	namespace	std;
#define size 2005
int mini(int a,int b)
{
    return a<=b?a:b;		//取二者中较小值 
}
int comp(const void *a,const void *b)
{
	return *(int *)a-*(int *)b;// 从小到大排序
}
int	cost[size][1005];//物品,次数 
int	main()
{
	int	n,k;//几件物品,搬几趟
	while(cin>>n>>k)
	{
		long	long	arr[size];
		int i,j;
		memset(arr,0,sizeof(arr));
		for(int	i=1;i<=n;i++)
			cin>>arr[i];
		qsort(arr+1,n,sizeof(arr[0]),comp);
		//初始化结果数组 
		for(int	i=0;i<=n;i++)
			for(int	j=1;j<=k;j++)
				cost[i][j]= 2147483641;//最大化处理 (除所有搬0次的可能) 
		cost[0][0]=0;
		//开始计算 
		for(j=2; j<=n; j++)//物品数 
            for(i=1; i*2<=j; i++)//次数 
				cost[j][i]=mini(cost[j-1][i],cost[j-2][i-1]+(arr[j]-arr[j-1])*(arr[j]-arr[j-1]));
		cout<<cost[n][k]<<endl;
	} 
}

此类DP算法整体还是运用到递推思想,通过底层逐步上升求出最终的要求解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值