HDU 1412 搬寝室 DP

来源:互联网 发布:数据分析下载-搜狗应用 编辑:程序博客网 时间:2024/05/22 06:21

题意:。。。

题解:

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

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


原创粉丝点击