您的位置:首页 > 其它

NOJ——1656搬砖(DP)

2016-03-07 12:49 176 查看


[1656] 搬砖

时间限制: 2000 ms 内存限制: 65535 K

问题描述

开学了,万恶的大二学长们又要领着大一的鲜肉们一起敲代码搬砖了,这不,著名的杨神拿着n块砖头,当然他把这n块砖头的重量都告诉你了,让你搬走其中的2*k块,其中每次你只能拿2块,消耗的体力是这两块砖头重量之差的平方,比如一块砖重量为5,另一块是11,那么搬走这两块砖头消耗体力为(11- 5)^2 = 36,机智如你,你能算出如何搬2*k块,才能使你花费的体力最小呢?

输入

一个整数t,代表数据组数(t <= 10)

每组数据包含2个整数n和k,保证0 <= 2*k <= n <= 2000

接下来一行包含n个整数(每个数都<= 100000)

输出

每组一个整数,代表最小的体力消耗

样例输入

2
2 1
1 3
6 2
1 4 2 6 11 9


样例输出

4
5


提示

第二组样例,可以这么搬(1 2) (4 6)组合,或者(1 2) (9 11)组合,这样花费代价是最少的


这题在我看了很久的大神的题解+想了又想之后稍微理解了点,写了下代码......还好过了
让我这个初学者菜鸟神烦的一题...
主要思想:由于平方差最小,那么你sort之后一定是取相邻的一对数字,但是向左或向右就不得而知了,因此要用二位数组记录当前循环到第i件时取了j对所消耗的体力。
两层for是因为每一次可选i件都会对当前的最优解造成影响,但是可以记录在那一次的dp[i]中,因此最后那个dp
[k]就是可选n件时取k对的最优解
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<map>
#include<sstream>
#include<algorithm>
#include<cmath>
using namespace std;
int zhuan[2010];
int dp[2010][2010];//
int main (void)
{
int t,n,k,i,j,ans;
cin>>t;
while (t--)
{
cin>>n>>k;
memset(zhuan,0,sizeof(zhuan));
memset(dp,0x3f3f3f3f,sizeof(dp));
for (int i=0; i<n; i++)
{
cin>>zhuan[i];
dp[i][0]=0;
}
sort(zhuan,zhuan+n);
for (int i=1; i<=n; i++)//当前循环到的第I件(不一定选)
{
for (int j=1; 2*j<=i&&j<=k; j++)//(当成功入选j件时)
{
dp[i][j]=min(dp[i-2][j-1]+(zhuan[i-2]-zhuan[i-1])*(zhuan[i-2]-zhuan[i-1]) , dp[i-1][j]);	                          //最优决策=min(上一次状态+取i-1与i-2这两件/不取,保持上一件状态)
}
}
cout<<dp
[k]<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: