首页 > 代码库 > hdoj 1421 搬寝室 【dp】

hdoj 1421 搬寝室 【dp】

题意。。。

首先从小到大排个序,并且分析之后可得, 如果要去第i个的话,则第i-1个物品也要取(因为是排过序的与i相差最小的就是i-1或者是i+1, 但是i+1与i也可以看做i和i-1, 所以如果要去第i个的话,则第i-1个物品也要取)。

分析:设dp[i][j]表示有i个物品,拿j对。则第i个物品对dp[i][j]有两种情况:

一:如果要不取第i个物品, 则此时的dp[i][j] = dp[i-1][j](仔细考虑一下)

二:如果要取第i个物品, 则此时有dp[i][j] = dp[i-2][j-1]+pow2(s[i]-s[i-1])(因为如果要去第i个的话,则第i-1个物品也要取,所以就是i-2,又因为又取了一对,所以是j-1);

注1:又因为是要找最小的疲劳值,所以取上面两种情况的最小值。

注2:初始化的时候dp[i][0] = 0,其他的都初始化为较大的数


代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define M 2050
#define INF 0x7f7f7f7f
using namespace std;
int s[M];
int dp[M][M];

int pow2(int x){
	return x*x;
}

void solve(int n, int m){
	int i, j;
	for(i = 1; i <= n; i ++){
		for(j = 1; j <= n/2; j ++){
			dp[i][j] = INF;
		}
		dp[i][0] = 0;
	}
	for(i = 2; i <= n; i ++){
		for(j = 1; j <= i/2; j ++){
			dp[i][j] = min(dp[i-1][j], dp[i-2][j-1]+pow2(s[i]-s[i-1]));
		}
	}
	printf("%d\n", dp[n][m]);
}

int main(){
	int n, m, i;
	while(scanf("%d%d", &n, &m) == 2){
		for(i = 1; i <= n; i ++){
			scanf("%d", &s[i]);
		}
		sort(s+1, s+n+1);
		solve(n, m);
	}
	return 0;
}

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1421

hdoj 1421 搬寝室 【dp】