hdu5492 find the path dp

这是去年合肥的另一道签到。。。题目其实很简单。。。仔细想想范围就能推出来了,第一二维存位置,但显然不够,所以开第三维,由于空间限制只能在和以及平方和二选一,由于平方和太大,所以只能存和。然后dp的值如果存为方差*n的话,显然还需要一维存平方和,但仔细看看式子,如果和以及平方和知道了,也就知道方差了,而方差是很难处理的,事实上,当和固定的时候,平方和越小,方差*n也就越小,这个可以将式子展开得到,所以直接用dp的值来存平方和,先求出和为sum的情况下的最小平方和,然后再枚举sum就可以了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define key_val ch[ch[rt[i]][1]][0]

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

int n,m;
int a[40][40];
int dp[32][32][2200];

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif
    int casen=1;
    int T;cin>>T;
    while(T--){
        scanf("%d%d",&n,&m);
        REP(i,1,n) REP(j,1,m) scanf("%d",&a[i][j]);
        REP(i,1,n) REP(j,1,m) REP(sum,0,1810) dp[i][j][sum]=INF;
        dp[1][1][a[1][1]]=a[1][1]*a[1][1];
        REP(i,1,n){
            REP(j,1,m){
                REP(sum,a[i][j],1810){
                    if(i==1&&j==1) continue;
                    dp[i][j][sum]=INF;
                    if(i>1)
                        dp[i][j][sum]=min(dp[i][j][sum],dp[i-1][j][sum-a[i][j]]+a[i][j]*a[i][j]);
                    if(j>1)
                        dp[i][j][sum]=min(dp[i][j][sum],dp[i][j-1][sum-a[i][j]]+a[i][j]*a[i][j]);
                }
            }
        }
        ll ans=INF;
        REP(sum,0,1810){
            ll tmp=1LL*(n+m-1)*dp[n][m][sum]-sum*sum;
            ans=min(ans,tmp);
        }
        printf("Case #%d: %I64d\n",casen++,ans);
    }
    return 0;
}
View Code

 

posted @ 2016-02-23 19:54  __560  阅读(279)  评论(0编辑  收藏  举报