您的位置:首页 > 其它

HDU 1412 搬寝室 DP

2013-05-19 20:48 267 查看
题意:。。。

题解:

将所有的数从小到大排序。

证明一个性质:若一个数num[i]被选中,那么一定要选num[i-1]或者num[i+1]来与它配对,这样才能使差方最小。

例如有下面四个数,他们从小到大到分别为x, x+a, x+a+b, x+a+b+c

选择(x,x+a),(x+a+b,x+a+b+c) ,差方=a^2+c^2

选择 (x,x+a+b), (x+a,x+a+b+c),差方=(a+b)^2+(b+c)^2

选择(x,x+a+b+c),(x+a,a+a+b),差方= b^2+(a+b+c)^2

则a^2+c^2 < (a+b)^2+(b+c)^2 且 a^2+c^2 < b^2+(a+b+c)^2

//先排序,假设从n-1个中选取k对是最少得,那么从n个中选取k对,可以这样分析 对n-1个数 再在末尾增加一个数,那么这个数可能被选中成为k对中其中一对,可能不被选中,如果不被选中,那么从n个中选取k对就相当于从n-1个中选取k对,如果被选中,之前证明了选中的数必须是连续的两个才能事最小,那就相当于从n-2个数中选取k-1对加最后两个数成为,这样,状态转移方程就为dp[i%3][j]=min(dp[(i-1)%3][j],dp[(i-2)%3][j-1]+(a[i-1]-a[i])*(a[i-1]-a[i]));

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

#define lint __int64
#define MAXN 2001
lint dp[3][MAXN];
lint n, k, a[MAXN];

int main()
{
while(scanf("%I64d%I64d", &n,&k) != EOF)
{
for(int i = 1; i <= n; i++)
scanf("%I64d", &a[i]);

sort(a + 1, a + 1 + n);
memset(dp, 0, sizeof(dp));
for(int i = 2; i <= n; i++)
{
if(i % 2 == 0)
{
int t = i / 2;
for(int j = 1; j < t && j <= k; j++)
dp[i%3][j] = min(dp[(i-1)%3][j], dp[(i-2)%3][j-1] + (a[i-1]-a[i])*(a[i-1]-a[i]));

if(t <= k)
dp[i%3][t] = dp[(i-2)%3][t-1] + (a[i-1]-a[i])*(a[i-1]-a[i]);
}
else
{
int t = i / 2;
for(int j = 1; j <= t && j <= k; j++)
dp[i%3][j] = min(dp[(i-1)%3][j], dp[(i-2)%3][j-1] + (a[i-1]-a[i])*(a[i-1]-a[i]));
}
}
printf("%I64d\n", dp[n%3][k]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: