hdu 3480

斜率dp

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 10005
#define maxm 5005
using namespace std;
int dp[maxn][maxm];
int q[maxn*10];
int num[maxn];

bool check(int j,int tail,int i)
{
    int yk=dp[q[tail-1]][j-1]+num[q[tail-1]+1]*num[q[tail-1]+1];
    int yj=dp[q[tail]][j-1]+num[q[tail]+1]*num[q[tail]+1];
    int yi=dp[i][j-1]+num[i+1]*num[i+1];
    int xk=2*num[q[tail-1]+1];
    int xj=2*num[q[tail]+1];
    int xi=2*num[i+1];
    if((yi-yk)*(xj-xk)<=(yj-yk)*(xi-xk))return 1;
    return 0;
}

bool get(int head,int j,int i)
{
    int y1=dp[q[head]][j-1]+num[q[head]+1]*num[q[head]+1];
    int y2=dp[q[head+1]][j-1]+num[q[head+1]+1]*num[q[head+1]+1];
    int x1=num[q[head]+1];
    int x2=num[q[head+1]+1];
    if((y2-y1)<=2*num[i]*(x2-x1))return 1;
    return 0;
}

int main()
{
    int n,m,t;
    int ca=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&num[i]);
        sort(num+1,num+n+1);
        int tail,head;
        for(int i=1;i<=n;i++)
            dp[i][1]=(num[i]-num[1])*(num[i]-num[1]);
        for(int j=2;j<=m;j++)
        {
            head=tail=0;
            q[++tail]=j-1;
            for(int i=j;i<=n;i++)
            {
                while(tail-head>1&&check(j,tail,i))tail--;
                q[++tail]=i;
                while(tail-head>1&&get(head+1,j,i))head++;
                int best=q[head+1];
                dp[i][j]=dp[best][j-1]+(num[i]-num[best+1])*(num[i]-num[best+1]);

            }
        }
        printf("Case %d: %d\n",ca++,dp[n][m]);
    }
    return 0;
}
View Code

 四边形不等式优化:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 10005
#define maxm 5005
#define inf 99999999
using namespace std;

int dp[maxn][maxm];
int s[maxn][maxm];
int num[maxn];

int main()
{
    int n,m;
    int t,ca=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
            scanf("%d",&num[i]);
        sort(num+1,num+1+n);
        dp[0][0]=1;
        for(int i=1; i<=n; i++)
        {
            dp[i][1]=(num[i]-num[1])*(num[i]-num[1]);
        }
        for(int j=2; j<=m; j++)
        {
            s[n+1][j]=n-1;
            for(int i=n; i>=j; i--)
            {
                dp[i][j]=inf;
                for(int k=s[i][j-1]; k<=s[i+1][j]; k++)
                {
                    int tmp=dp[k][j-1]+(num[i]-num[k+1])*(num[i]-num[k+1]);
                    if(dp[i][j]>tmp)
                    {
                        s[i][j]=k;
                        dp[i][j]=tmp;
                    }
                }
            }
        }
        printf("Case %d: %d\n",ca++,dp[n][m]);
    }
    return 0;
}
View Code

 


 

posted @ 2014-03-12 17:13  Yours1103  阅读(116)  评论(0编辑  收藏  举报