hdu 5492(dp)

题目描述:

给定一张30*30的图,图上每个点的权值不超过30,让你求

(N+M−1)∑N+M−1i=1(Ai−Aavg)2的最小值?

队友将这个式子化成了求方差D[x]=E(x^2)-E(x);

我猜测是DP,分析一下,这个式子并不具有最优子结构,假设可以经过AB

到达终点c,选取这两个点的方差的最小值,说明到达这两个点的序列最稳定,

假设A点是较优点,但是可能会出现,到达A点的最优序列加上c的序列,

没有到达A的某一个序列加上c的序列优(稳定)

可以直接化简这个式子得到(A1^2+A2^2+A3^2+...+A[n+m-1]^2*(n+m-1)-(A1+A2+A3+A4+...+A[n+m-1])^2;

观察一下我们可以维护和和平方和这两项,然后将到达某一个点的所有可能路径

,通过和来分类,d[x][y][k]表示到达xy这个点和为k的最小平方和。

 

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#define maxn 31
#define  LL long long
#define inf 0x3f3f3f3f3f3f
using namespace std;
int ans;
int d[maxn][maxn][1800];
int a[maxn][maxn];
int dir[2][2]={1,0,0,1};
int n,m;
struct node
{
    int x,y,k;
};
void init()
{
   for(int i=0;i<maxn;i++)
    for(int j=0;j<maxn;j++)
      for(int k=0;k<1800;k++)
        d[i][j][k]=inf;
}
void spfa()
{
    int visit[maxn][maxn];
    memset(visit,0,sizeof(visit));
    queue <node>  que;
    node start;
    start.x=1;  start.y=1;  start.k=a[1][1];
    d[1][1][a[1][1]]=a[1][1]*a[1][1];
    que.push(start);
    visit[1][1]=1;
    while(!que.empty())
    {
        node next,cur=que.front();   que.pop();
        for(int i=0;i<2;i++)
        {
            int x,y,k;
            next.x=x=cur.x+dir[i][0];
            next.y=y=cur.y+dir[i][1];
            next.k=k=cur.k+a[x][y];
            if(next.x>=1 && next.x<=n && next.y>=1 && next.y<=m)
            {
                int temp=d[cur.x][cur.y][cur.k]+a[x][y]*a[x][y];
                if(temp<d[x][y][k])
                {
                   d[x][y][k]=temp;
                    if(visit[x][y]==1)
                        continue;
                    que.push(next);
                    visit[1][1]=1;
                }
            }
        }
    }
}
int main()
{
    // freopen("test.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int  t;
    scanf("%d",&t);
    int cas = 0;
    while(t --)
    {
        init();
         scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
             scanf("%d",&a[i][j]);
        //work();
        spfa();
        ans=inf;
        for(int k=0;k<=30*59;k++)
        {
           if(d[n][m][k]==inf)
            continue;
           int temp=(n+m-1)*d[n][m][k]-k*k;
           if(temp<=ans && temp>=0)
                ans=temp;
        }
        printf("Case #%d: %d
",++cas,ans);
    }
    return 0;
}

 

 

原文地址:https://www.cnblogs.com/xianbin7/p/4844847.html