hdu 5492 Find a path(dp)

来源:互联网 发布:奇幻咔咔差不多的软件 编辑:程序博客网 时间:2024/06/04 17:59

题目链接:hdu 5492 Find a path

解题思路

动态规划。首先化简出公式

F(n)=ni=1n(x2i)(i=1nxi)2


P(n)=i=1n(x2i)

S(n)=(i=1nxi)

则有
F(n)=nP(n)S(n)2

S(n)最大为59 * 30,所以dp[i][j][k]表示在第i行j列这个位置,S = k时,P(n)的最小值。

优化,起始每个i,j的S值有一个范围,预先处理一下即可,注意范围中的每个位置不一定可以转移到。

代码

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int maxn = 35;const int maxm = 1800;const int inf = 0x3f3f3f3f;int N, M, W[maxn][maxn], dp[maxn][maxn][maxm];int up[maxn][maxn], dn[maxn][maxn];void init () {    memset(up, 0, sizeof(up));    memset(dn, inf, sizeof(dn));    scanf("%d%d", &N, &M);    for (int i = 1; i <= N; i++) {        for (int j = 1; j <= M; j++) {            scanf("%d", &W[i][j]);            up[i][j] = max(up[i-1][j], up[i][j-1]) + W[i][j];            dn[i][j] = min(dn[i-1][j], dn[i][j-1]) + W[i][j];            if (i == 1 && j == 1)                up[i][j] = dn[i][j] = W[i][j];        }    }}int solve () {    memset(dp, inf, sizeof(dp));    dp[1][1][W[1][1]] = W[1][1] * W[1][1];    for (int i = 1; i <= N; i++) {        for (int j = (i == 1 ? 2 : 1); j <= M; j++) {            for (int k = dn[i][j]; k <= up[i][j]; k++) {                int& tmp = dp[i][j][k];                if (dp[i-1][j][k-W[i][j]] != inf)                    tmp = min(tmp, dp[i-1][j][k-W[i][j]]);                if (dp[i][j-1][k-W[i][j]] != inf)                    tmp = min(tmp, dp[i][j-1][k-W[i][j]]);                if (tmp != inf)                    tmp += W[i][j] * W[i][j];            }        }    }    int ret = inf;    for (int i = dn[N][M]; i <= up[N][M]; i++)        if (dp[N][M][i] != inf)            ret = min(ret, (N+M-1) * dp[N][M][i] - i * i);    return ret;}int main () {    int cas;    scanf("%d", &cas);    for (int kcas = 1; kcas <= cas; kcas++) {        init();        printf("Case #%d: %d\n", kcas, solve());    }    return 0;}
0 0
原创粉丝点击