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

来源:互联网 发布:js修改style属性值 编辑:程序博客网 时间:2024/06/05 10:06

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;}
2 0
原创粉丝点击