蓝桥杯历届试题 地宫取宝 dp or 记忆化搜索

问题描述

  X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
  地宫的入口在左上角,出口在右下角。
  小明被带到地宫的入口,国王要求他只能向右或向下行走。
  走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
  当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
  请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。

输入格式

  输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)
  接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值

输出格式

  要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。

样例输入

2 2 2
1 2
2 1

样例输出

2

样例输入

2 3 2
1 2 3
2 1 5

样例输出

14

暴力dfs会超时,可以dp或者记忆化搜索....理解可以...自己写可能就....gg了...

这样的话,感觉还是记忆化搜索更萌一些,因为不用考虑那么多边界...

思路见代码.

dp:

/*
蓝桥杯历届试题地宫寻宝

dp
状态:dp[i][j][num][val] 表示从起点(1, 1)走到(i, j), 已经取了num个宝物,最大价值是val 的方案数。
初态:dp[1][1][0][0] = 1; dp[1][1][1][mp[1][1]] = 1;
转移方程:由上方或者左方的格子转移而来,详见代码;
*/

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;

#define mod 1000000007
int dp[55][55][15][15];
int mp[55][55];

int main() {
    int n, m, k;
    while(~scanf("%d%d%d", &n, &m, &k)) {
        for (int i=1; i<=n; ++i) {
            for (int j=1; j<=m; ++j) {
                scanf("%d", &mp[i][j]);
            }
        }

        memset(dp, 0, sizeof(dp));
        dp[1][1][0][0] = 1;
        dp[1][1][1][mp[1][1]] = 1;

        for (int i=1; i<=n; ++i) {
            for (int j=1; j<=m; ++j) {
                dp[i][j][0][0] += (dp[i-1][j][0][0] + dp[i][j-1][0][0]);
                dp[i][j][0][0] %= mod;
                for (int num=1; num<=k; ++num) {
                    for (int val=0; val<=12; ++val) {
                        dp[i][j][num][val] += (dp[i-1][j][num][val] + dp[i][j-1][num][val]);
                        dp[i][j][num][val] %= mod;
                    }
                    if (num == 1) {
                        dp[i][j][1][mp[i][j]] += dp[i-1][j][0][0];
                        dp[i][j][1][mp[i][j]] %= mod;
                        dp[i][j][1][mp[i][j]] += dp[i][j-1][0][0];
                        dp[i][j][1][mp[i][j]] %= mod;
                    }
                    else {
                        for (int t=0; t<mp[i][j]; ++t) {
                            dp[i][j][num][mp[i][j]] += dp[i-1][j][num-1][t];
                            dp[i][j][num][mp[i][j]] %= mod;
                            dp[i][j][num][mp[i][j]] += dp[i][j-1][num-1][t];
                            dp[i][j][num][mp[i][j]] %= mod;
                        }
                    }
                }
            }
        }

        int ans = 0;
        for (int i=0; i<=12; ++i) {
            ans += dp[n][m][k][i];
            ans %= mod;
        }
        printf("%d\n", ans);
    }
    return 0;
}

记忆化搜索:

/*
蓝桥杯历届试题 地宫取宝

dp[i][j][num][k] 表示到位置(i, j)时, 取了第num个宝藏,最大宝藏值是k时,
能到终点的路线方案数。

dfs超时。
记忆化搜索...
*/

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define mod 1000000007

int dp[55][55][15][15];
int n, m, k;
int mp[55][55];

int dfs(int nowx, int nowy, int cnt, int nowMax) {
    if (dp[nowx][nowy][cnt][nowMax+1] != -1) {
        return dp[nowx][nowy][cnt][nowMax+1];
    }
    int ans = 0;
    if (nowx == n-1 && nowy == m-1) {
        if (mp[nowx][nowy] > nowMax) {
            if (cnt == k || cnt == k-1)
                ans++;
            ans %= mod;
        }
        else if (cnt == k) ans++;
        ans %= mod;
        return dp[nowx][nowy][cnt][nowMax+1] = ans;
    }

    if (nowx+1 < n) {
        if (mp[nowx][nowy] > nowMax) {
            ans += dfs(nowx+1, nowy, cnt+1, mp[nowx][nowy]);
            ans %= mod;
        }
        ans += dfs(nowx+1, nowy, cnt, nowMax);
        ans %= mod;
    }
    if (nowy+1 < m) {
        if (mp[nowx][nowy] > nowMax) {
            ans += dfs(nowx, nowy+1, cnt+1, mp[nowx][nowy]);
            ans %= mod;
        }
        ans += dfs(nowx, nowy+1, cnt, nowMax);
        ans %= mod;
    }
    return dp[nowx][nowy][cnt][nowMax+1] = ans;
}

int main() {
    while(~scanf("%d%d%d", &n, &m, &k)) {
        memset(dp, -1, sizeof(dp));
        for (int i=0; i<n; ++i) {
            for (int j=0; j<m; ++j) {
                scanf("%d", &mp[i][j]);
            }
        }
        int ans = dfs(0, 0, 0, -1);
        printf("%d\n", ans);
    }
    return 0;
}

  

时间: 2024-10-13 00:46:56

蓝桥杯历届试题 地宫取宝 dp or 记忆化搜索的相关文章

蓝桥杯 历届试题 地宫取宝 【记忆化搜索】

历届试题 地宫取宝 时间限制:1.0s   内存限制:256.0MB 问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿). 当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明. 请你帮小明算一算,在给定的局面下,他有多少种不同的

蓝桥杯竞赛题《地宫取宝》DP做法

问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿). 当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明. 请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝. 输入格式 输入一行3个整数,用空格分开:n

蓝桥杯 历届试题 题目总结

后天就是蓝桥杯省赛了,今天总结一下这段时间做的蓝桥杯历届试题,还是一个一个题目的来吧!!!!!! 1,历届试题 矩阵翻硬币 这个题目说真的,我不会,在网上看了某神牛的题解答案为 ans=sqrt(n)*sqrt(m),具体怎么证明的我也不知道 2,历届试题 兰顿蚂蚁 这个题目怎么说呢,应该是送分题,直接模拟就可以了,这里就不说了. 3, 历届试题 分糖果 这个题目好像之前在哪里做过,也是一道模拟题,弄两个数组搞一下就可以了 下面是代码 #include<bits/stdc++.h> using

蓝桥杯-历届试题之大臣的旅费

历届试题 大臣的旅费 时间限制:1.0s   内存限制:256.0MB 问题描述 很久以前,T王国空前繁荣.为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市. 为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达.同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的. J是T国重要大臣,他巡查于各大城市之间,体察民情.所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情.他有一个钱袋,用于

Codeforces 509F Progress Monitoring (区间dp 或 记忆化搜索)

F. Progress Monitoring time limit per test 1 second memory limit per test 256 megabytes Programming teacher Dmitry Olegovich is going to propose the following task for one of his tests for students: You are given a tree T with n vertices, specified b

POJ 1958 Strange Towers of Hanoi (线性dp,记忆化搜索)

JQuery工具方法. (1)$.isNumeric(obj) 此方法判断传入的对象是否是一个数字或者可以转换为数字. isNumeric: function( obj ) { // parseFloat NaNs numeric-cast false positives (null|true|false|"") // ...but misinterprets leading-number strings, particularly hex literals ("0x...&

POJ 1958 Strange Towers of Hanoi (四塔问题,线性dp,记忆化搜索)

题目分析:四柱汉诺塔.由于题目已经给出了求解方法,直接写代码即可.下面总结一下,四塔问题. 感谢这篇文章的作者,点这里就到,总结的很好.直接贴过来~ 四塔问题:设有A,B,C,D四个柱子(有时称塔),在A柱上有由小到大堆放的n个盘子. 今将A柱上的盘子移动到D柱上去.可以利用B,C柱作为工作栈用,移动的规则如下: ①每次只能移动一个盘子. ②在移动的过程中,小盘子只能放到大盘子的上面. 设计并实现一个求解四塔问题的动态规划算法,并分析时间和空间复杂性. 算法思想: 用如下算法移动盘子(记为Fou

poj1179 区间dp(记忆化搜索写法)有巨坑!

http://poj.org/problem?id=1179 Description Polygon is a game for one player that starts on a polygon with N vertices, like the one in Figure 1, where N=4. Each vertex is labelled with an integer and each edge is labelled with either the symbol + (add

HDU--1142--A Walk Through the Forest--深广搜/DP/最短路径/记忆化搜索

A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5948    Accepted Submission(s): 2191 Problem Description Jimmy experiences a lot of stress at work these days, especial