zoukankan      html  css  js  c++  java
  • HDU5492 Find a path (dp)

    参考:http://blog.csdn.net/u014679804/article/details/48769267   膜拜大神!

    题目大意:给N*M(1<=N,M<=30)的矩阵,矩阵的每一格有一个非负权值(<=30)

    从(1,1)出发,每次只能向右或向下移动,到达(n,m)时,经过的格子的权值形成序列A,

    将式子展开后,化简整理可得:(N+M-1)*s1-s2。其中s1是序列A的平方和,s2是序列A的和的平方。

    注意到序列A的和不会超过(30+30-1)*30。

    设dp[i][j][k]表示到达(i,j),序列和为k时,序列的平方和的最小值。

    那么很容易得到状态转移方程,对于向右走,有:dp[i][j+1][k+V[i][j+1]]=min(dp[i][j+1][k+V[i] [j+1]],dp[i][j][k]+V[i][j+1]*V[i][j+1]),V[i][j]为(i,j)的值,类似地,可得到向下走的状态转移方 程。

    最终,枚举(n+m-1)*dp[n][m][k]-k^2,0<=k<=59*30,取最小值即为答案。

    注意dp的初始化,枚举序列A的和的时候,有些和是不会出现的,即有些状态是无法到达的。因此将dp全部初始化为inf,第(1,1)格的值初始化为V[1][1]^2,然后求解各个状态的值。

    附上参考过后的代码:

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <vector>
    #include <cstdio>
    using namespace std;
    #define inf 0x3f3f3f3f
    int dp[30][30][1800];
    int v[30][30];
    int fun(int x)
    {
        return x*x;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int t,cas=1;
        scanf("%d",&t);
        while(t--)
        {
            memset(dp,inf,sizeof(dp));
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=0; i<n; i++)
                for(int j=0; j<m; j++)
                    scanf("%d",&v[i][j]);
            dp[0][0][v[0][0]]=fun(v[0][0]);
            for(int i=0; i<n; i++)
            {
                for(int j=0; j<m; j++)
                {
                    if(i==n-1&&j==m-1) break;
                    for(int k=0; k<1800; k++)
                    {
                        if(dp[i][j][k]!=inf)
                        {
                            if(i+1<n) dp[i+1][j][k+v[i+1][j]]=min(dp[i+1][j][k+v[i+1][j]],dp[i][j][k]+fun(v[i+1][j]));
                            if(j+1<m) dp[i][j+1][k+v[i][j+1]]=min(dp[i][j+1][k+v[i][j+1]],dp[i][j][k]+fun(v[i][j+1]));
                        }
                    }
                }
            }
            int ans=inf;
            for(int i=0; i<1800; i++)
                if(dp[n-1][m-1][i]!=inf)
                    ans=min(ans,(n+m-1)*dp[n-1][m-1][i]-fun(i));
            printf("Case #%d: %d
    ",cas++,ans);
        }
        return 0;
    }
  • 相关阅读:
    安利一个_Java学习笔记总结
    九涯的第一次
    attrs 资源文件 自定义属性
    EditText
    ArrayList 数组 初始化方法
    HTTP Retrofit 网络传输
    画布Canvas 画笔Paint
    View控件跟随鼠标移动
    ViewPager和Fragment中的View的点击事件冲突
    圆形图片 ImageView
  • 原文地址:https://www.cnblogs.com/d-e-v-i-l/p/4843573.html
Copyright © 2011-2022 走看看