hdu1421n中选k个不相邻数的最小值
来源:互联网 发布:考研作息知乎 编辑:程序博客网 时间:2024/04/29 01:09
//题目大意:有n个物品.每个物品有重量.一个人需要搬动k次物品.每次用两只手搬动.消耗疲劳值为左右手重量差的平方.// 求消耗疲劳的最小值//解题思路:自己做的时候把n个物品转换成n-1个物品.转换通过把n个物品排序.依次相减平方.那么所选的k个值// 必定是从这n-1个中选出来的..同时要求k个值没有任意两个是相邻的.// dp转移方程为dp[i][j][0] 表示前i件物品中选择j件物品.第三维0,1分别表示是否选择最后一个.// 那么dp[i][j][0] = min(dp[i-1][j][0] , dp[i-1][j][1]);// dp[i][j][1] = dp[i-1][j-1][0] + cas[i];// 同时由于第i次只与第i-1次有关.所以可以采用滚动数组的办法.// 后来看了网上的代码.这是一个经典的dp问题.dp[i][j] = min(dp[i-1][j] , dp[i-2][j-1] + cas[i]);// 对于dp经典问题.要融会贯通其dp转移方程.许多dp题目都是源自于一些经典的dp问题转移方程.// 转移方程翻译过来就是dp[i][j]的值源自于两种情形.前i-1个中选择j个的最优值.和前i-2个中选择j-1个的// 最优值.dp[i-1][j]就相当于默认不选择第j个dp[i-2][j-1]就相当于默认选择第i个.// 而不用像我自己的转移方程那样去分开来讨论..//题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1421 以下是自己转移方程写的和标准转移方程写的题目#include<stdio.h>#include<stdlib.h>#include<iostream>#include<math.h>#include<vector>#include<algorithm>#include<stack>#include<queue>#include<string.h>using namespace std;int n,k;int dp[4][2222][4],f[2002][1001];int a[2222],cas[2222];int main(){ while(scanf("%d%d",&n,&k) != EOF) { for(int i = 1 ; i <= n ; i++)scanf("%d",&a[i]); sort(a+1,a+n+1); for(int i = 1 ; i < n ; i++) cas[i] = (a[i+1] - a[i]) * (a[i+1] - a[i]); memset(f,0x3f3f3f3f,sizeof(f));// for(int i = 0 ; i < n ; i++)f[i][0] = 0;// f[1][1] = cas[1];// for(int i = 2 ; i < n ; i++)// for(int j = 1 ; j * 2 <= i + 1; j++)// f[i][j] = min(f[i-1][j] , f[i-2][j-1] + cas[i]);// cout<<f[n-1][k]<<endl;// 自己的做法: memset(dp,0x3f3f3f3f,sizeof(dp)); dp[0][0][0] = 0; dp[0][1][0] = 0x3f3f3f; dp[0][1][1] = cas[1]; for(int i = 2 ; i < n ; i++) { for(int j = 1 ; j <= (i+1)/2 ; j++) { dp[1][j][0] = min(dp[0][j][0] , dp[0][j][1]); dp[1][j][1] = dp[0][j-1][0] + cas[i]; } for(int j = 1 ; j <= (i+1)/2 ; j++) { dp[0][j][0] = dp[1][j][0]; dp[0][j][1] = dp[1][j][1]; } } printf("%I64d\n",min(dp[0][k][1],dp[0][k][0])); }}