DP(1) --- 数塔

来源:互联网 发布:js 业务逻辑 模块 编辑:程序博客网 时间:2024/06/15 18:01

数塔问题

1. 基本模型 (HDU 2084)

        
 

如上图所示数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

数塔思想:自顶向下分析,自底向上计算

      H(i) 表示第i层的最大值。要得到Hi + 1),则考虑上一层结点,到其相邻节点可取得的值,取最大值作为H(i + 1)

     如果按照上述做法,从顶到底算起,则时间复杂度为 O(2^(n – 1))

     考虑从底部算起,计算每个结点到底层的最大值,即上一层结点与其相邻节点的最大值,以这个最大值作为上一层结点的值,重复这一过程,直到塔顶。时间复杂度为On)

2. 简单应用

  a. 多少条路径 (HDU 2151)
    猴子爬树,最初猴子在第一棵树上,每过一分钟,猴子会跳到相邻的树上。现在这里有n棵树,求过了m分钟,有多少种不同的跳法跳到第T棵树。(HDU2151考虑以下图形, 是不是很像一个数塔?
  b. 多顶点型数塔(例题 HDU 1176)

    免费馅饼,有010个位置,起始时,人在5处,每一秒都会有几个馅饼落下来,每秒人可以移动到相邻的位置,问最多可以接多少个馅饼?考虑如下算法:

          dp[i][j] 表示从第i秒起第j个位置可得到的馅饼;
          pie[i][j] 表示第i秒第j个位置落下的馅饼
          从最后一秒算起,dp[i][j] = maxdp[i + 1][j], maxdp[i + 1][j - 1],  dp[i + 1][j + 1]))+ pie[i][j]
          重复这一过程知道t = 0;最后这会形成一个多顶点的数塔,每个位置都是一个顶点。
 
3. 例题代码
HDU 2084
#include <stdio.h>int tower[100][100];int main(){int i, j;int T, N;int v1, v2;scanf ("%d", &T);while (T --){scanf ("%d", &N);for (i = 1; i <= N; i ++){for (j = 1; j <= i; j ++){scanf ("%d", &tower[i][j]);}}for (i = N - 1; i >= 1; i --)   // 自底向上计算每一层的最大值{for (j = 1; j <= i + 1; j ++){v1 = tower[i + 1][j] + tower[i][j];v2 = tower[i + 1][j + 1] + tower[i][j];tower[i][j] = v1;if (v1 < v2){tower[i][j] = v2;}}}printf ("%d\n", tower[1][1]);}return 0;}
HDU 2151
 
#include <stdio.h>#include <string.h>int main(){int i, j, k;int numbers;int N, P, M, T;int tree[2][101];int times[2][101];while (scanf ("%d%d%d%d", &N, &P, &M, &T) == 4){memset (times, 0, sizeof (times));tree[0][0] = P;times[0][P] = 1;numbers = 1;k = 0;while (M --){j = 0;k %= 2;for (i = 0; i < numbers; i ++){if (tree[k][i] > 1){if (times[k ^ 1][tree[k][i] - 1] == 0){tree[k ^ 1][j ++] = tree[k][i] - 1;}times[k ^ 1][tree[k][i] - 1] += times[k][tree[k][i]];}if (tree[k][i] < N){if (times[k ^ 1][tree[k][i] + 1]== 0){tree[k ^ 1][j ++] = tree[k][i] + 1;}times[k ^ 1][tree[k][i] + 1] += times[k][tree[k][i]];}times[k][tree[k][i]] = 0;}numbers = j;k ++;}printf ("%d\n", times[k % 2][T]);}return  0;}
HDU 1176
 
#include <stdio.h>#include <string.h>#define MAX 100002int pie[MAX][13];int dp[MAX][13];int max_v (int a, int b);int main(){int n;int i, j;int t, x;int max_t;while (scanf ("%d", &n) == 1 && n){memset (pie, 0, sizeof (pie));memset (dp, 0, sizeof (dp));max_t = 0;for (i = 0; i < n; i ++){scanf ("%d%d", &x, &t);if (max_t < t){max_t = t;}pie[t][x + 1] ++;}for (i = max_t; i >= 0; i --){for (j = 1; j < 12; j ++){dp[i][j] = max_v (dp[i + 1][j - 1], max_v (dp[i + 1][j], dp[i + 1][j + 1])) + pie[i][j];}}printf ("%d\n", dp[0][6]);}return 0;}int max_v (int a, int b){if (a > b){return a;}return b;}
 
原创粉丝点击