HDU 1412 搬寝室 DP

题意:。。。

题解:

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

证明一个性质:若一个数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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值