hdu3480 四边形不等式DP 解题报告

Division

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 999999/400000 K (Java/Others)
Total Submission(s): 4773 Accepted Submission(s): 1857

Problem Description

Little D is really interested in the theorem of sets recently. There’s a problem that confused him a long time.
Let T be a set of integers. Let the MIN be the minimum integer in T and MAX be the maximum, then the cost of set T if defined as (MAX – MIN)^2. Now given an integer set S, we want to find out M subsets S1, S2, …, SM of S, such that
and the total cost of each subset is minimal.

题解

四边形不等式做法:
首先这个由于排序后数字递增,所以显然w[i][j] = (j - i)^2是满足区间包含单调性的。
证明满足四边形不等式也比较直观:假设四个数为

x1 = a,x2 = a + b,x3 = a + b + c,x4 = a + b + c + d

,其中b,c,d为非负数;

w[x1][x3] + w[x2][x4] = (b + c)^2 + (c + d)^2 = b^2 + 2 * c^2 + d^2 + 2 * b * c + 2 * c * d;
w[x1][x4] + w[x2][x3] = (b + c + d)^2 + c^2 = b^2 + 2 * c^2 + d^2 + 2 * b * c + 2 * c * d + 2 * b * d;
=> w[x1][x3] + w[x2][x4] <= w[x1][x4] + w[x2][x3];

于是dp[][]就满足四边形不等式,于是s[i][j] <= s[i][j + 1] <= s[i + 1][j + 1],然后转移的时候取出s[i][j - 1]到s[i + 1][j]之间的k就可以了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=10000+10;
const int M=5000+10;
int a[N],dp[N][M],s[N][M];
int n,m,Case,T;
int main()
{
   scanf("%d",&T);
   while (T --)
   {
       scanf("%d%d",&n,&m);
       for (int i=1;i<=n;i++) 
       scanf("%d",&a[i]);
       sort(a+1,a+1+n);
       for (int i=1;i<=n;i++) 
       dp[i][1]=(a[i]-a[1])*(a[i]-a[1]),s[i][1]=1;
       for (int k=2;k<=m;k++)
       {
           s[n+1][k]=n-1;
           for (int i=n;i>=k;i--)
           {
               dp[i][k]=dp[k-1][k-1]+(a[i]-a[k])*(a[i]-a[k]);
               s[i][k]=k;
               for (int j=s[i][k-1];j<=s[i+1][k];j++)
               {
                   int tmp=dp[j][k-1]+(a[i]-a[j+1])*(a[i]-a[j+1]);
                   if (tmp<dp[i][k])
                   {
                       dp[i][k]=tmp;
                       s[i][k]=j;
                   }
               }
           }
       }
       printf("Case %d: %d\n",++ Case,dp[n][m]);
   }
   return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值