hdu1500

来源:互联网 发布:爱淘宝现金红包 编辑:程序博客网 时间:2024/05/18 17:45

看到这一题我刚开始想的时候也是好像觉得在哪里见过,但是想不起来,后来看到别人说的是hdu1421那个搬房子的题,两个题有很多的相似点,但是这一道题他的难度大一些,就是需要处理的地方稍微有一点拐弯。

       题目大意是有N支筷子,K个人,N>=k*3那么每个人需要选择3支筷子,满足A<B<C,其中A,B两只筷子的差的平方将作为对着三支筷子取得好坏的一个因素,C不管,我们应当使每个人都有三支筷子,而且最后的总的平方和最小,求出这个最好笑的数字。

我们说一般的DP题都有一个公共的情况那就是:走到某一步的时候要或者不要,这两个方向一般就是你建立状态方程的突破口。下面假设f[i][j]表示到第i支快走的时候第j个人在取,那么对于第i支筷子只有两种要和不要,如果要的话也就是第j个人选中这支筷子,那么这支筷子只能和前面一支搭配,因为后面一支还没出来而且他们的长短是有序的,这时候就是f[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]),a[i]表示筷子长度,不要的话那就是f[i-1][j]。但是这样有一个缺点就是,如果有一个数字为0他就可以一直不要,最后就是0,为了一定能取到,我们事先就让他取,再判断。

         还有一点就是这题必须从大到小,因为新来的一支是最大的,一定能取到,就是C,但是如果从大到小取到的就是最小的,多以不符合。

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstdlib>
#include<string.h>
using namespace std;
int a[5005];
int f[5005][1005];
int main()
{
   int T,k,N,i,j;
   int num,sum;
   cin>>T;
   while(T--)
   {
       cin>>k>>N;
       k+=8;
       for(i=N;i>=1;i--)
       scanf("%d",&a[i]);
       memset(f,0,sizeof(f));
        for(j=1;j<=k;j++)
        {
            i=j*3;
            f[i][j]=f[i-2][j-1]+(a[i-1]-a[i])*(a[i-1]-a[i]);//这里是确保每一个人都要取筷子。
          for(i++;i<=N;i++)
         f[i][j]=min(f[i-1][j],f[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]));    //i=3*j,也就是这时候一次性给你3根,然后你用后两个比较,前面一个就默认选择,如果是从小到大会有错误,如果这样大家都不理解的话,自己用数字带了试试看,就会明白的。
        }
        cout<<f[N][k]<<endl;
   }
   return 0;
}


0 0
原创粉丝点击