zoukankan      html  css  js  c++  java
  • hdu5492_枚举dp

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

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

    (N+M1)N+M1i=1(AiAavg)2

    的最小值。

     参考链接:http://blog.csdn.net/u014679804/article/details/48769267

    将式子展开后,化简整理可得:(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,然后求解各个状态的值。

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <cstdio>
     6 #include <vector>
     7 #include <ctime>
     8 #include <queue>
     9 #include <list>
    10 #include <set>
    11 #include <map>
    12 using namespace std;
    13 #define inf 0x3f3f3f3f
    14 typedef long long LL;
    15 
    16 int dp[40][40][1800], a[40][40];
    17 int main()
    18 {
    19     int t, n, m;
    20     scanf("%d", &t);
    21     for(int ca = 1; ca <= t; ca++)
    22     {
    23         scanf("%d %d", &n, &m);
    24         for(int i = 1; i <= n; i++)
    25             for(int j = 1; j <= m; j++)
    26                 scanf("%d", &a[i][j]);
    27         memset(dp, inf, sizeof(dp));
    28         dp[0][1][0] = 0;
    29         for(int i = 1; i <= n; i++)
    30         {
    31             for(int j = 1; j <= m; j++)
    32             {
    33                 for(int k = a[i][j]; k <=59 * 30; k++)
    34                 {
    35                     if(dp[i-1][j][k-a[i][j]] != inf)
    36                         dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k-a[i][j]]+a[i][j]*a[i][j]);
    37                     if(dp[i][j-1][k-a[i][j]] != inf)
    38                         dp[i][j][k]=min(dp[i][j][k],dp[i][j-1][k-a[i][j]]+a[i][j]*a[i][j]);
    39                 }                
    40             }
    41         }
    42         int res = inf;
    43         for(int i = 0; i <= 59 * 30; i++)
    44         {
    45             if(dp[n][m][i] != inf)
    46                 res = min(res, (n+m-1)*dp[n][m][i]-i*i);
    47         }
    48         printf("Case #%d: %d
    ", ca, res);
    49     }
    50     return 0;
    51 }
    View Code
  • 相关阅读:
    iptables之NAT端口转发设置
    Windows server 2008 R2远程桌面3389端口号修改
    Nginx启动错误:error while loading shared libraries: libpcre.so.1
    sp_change_users_login 'Update_One', '用户名', '登录名';
    Sqlserver 数据库定时自动备份
    ES DSL 基础查询语法学习笔记
    kafka命令使用
    kafka集群中常见错误的解决方法:kafka.common.KafkaException: Should not set log end offset on partition
    快速排序法(双冒泡排序法)
    运算符
  • 原文地址:https://www.cnblogs.com/luomi/p/5876924.html
Copyright © 2011-2022 走看看