地宫取宝|2014年蓝桥杯B组题解析第九题-fishers
地宫取宝
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
资源约定: 峰值内存消耗 < 256M CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。 注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型
思路:dfs模拟走格子,再出口处判断是否满足条件,这里出口处有细节点(代码中解释)
待改进:上面的思路超时了,只能过42%的数据。要用”记忆化搜索“改进(见文末)
代码一:
#include<iostream>
using namespace std;
long long ans = 0;
int arr[100][100];
int n,m,k;
int have[10010];
//判断是否能拿走当前坐标上的物件
bool canTake(int x,int y,int t){
for(int i=1;i<=t;i++){
if(have[i] >= arr[x][y]){
return false;
}
}
return true;
}
//dfs走格子
void dfs(int x,int y,int t){
if(x == n && y == m){
// (1)可能不算右下角的也正好
// (2)如果右下角的比当前的大,算上这一个如果正好也可以增加路径
if(t == k+1 || (t==k && canTake(n,m,t))){
ans++;
ans = ans % 1000000007;
}
return;
}
if(canTake(x,y,t)){
have[t] = arr[x][y];
if(x+1<=n){
dfs(x+1,y,t+1);
}
if(y+1<=m){
dfs(x,y+1,t+1);
}
have[t] = -1;
}
if(x+1<=n){
dfs(x+1,y,t); //走右边
}
if(y+1<=m){
dfs(x,y+1,t); //走下边
}
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>arr[i][j];
}
}
for(int i=1;i<=k;i++){
have[i] = -1;
}
dfs(1,1,1);//横坐标 纵坐标 件数
cout<<ans<<endl;
}
记忆型递归:就是“缓存”,使用数组或者map等等。存储当前状态对应的值(这里就是当前dfs参数下对应的方案数),
为什么要使用记忆型递归?因为中间结果重复过多,为了提高效率。
代码二:
#include <stdio.h>
#include <string.h>
#define N 1000000007
int n,m,k;
int map[50][50];
int dp[50][50][15][15];//dp数组中记录的是状态 xy坐标 拥有宝物数量 拥有宝物的最大值(这4个可以详尽唯一的描述没一种可能)
//如dp[3][4][5][6]=7 即当在map[3][4]且身上有5件宝物 宝物的最大值是6 是到达终点有7中路径
int dfs(int x,int y,int num,int max)//当前位置 拥有宝物的数量 拥有的宝物的最大值
{
if (dp[x][y][num][max]!=-1)//判断这个状态是否已经走过,如果走过就直接用记录的数值计算//因为宝物有可能为0所以定义max时用最小值-1 这就导致无法作为下标使用 实际上如果测试数据中宝物价值没有0
//将所有的+1 去掉也是可以的 这里的话如果去掉肯定是有些数据不对的,不信可以提交试一下,根本过不了
return dp[x][y][num][max];
//记忆化的记忆就指的是上面
if(x==n&&y==m){//到达出口
if( num==k||(num==k-1&&max<map[x][y]) ) //到达右下角,(1)可能不算右下角的也正好,(2)如果右下角的比当前的大,算上这一个如果正好也可以增加路径
return dp[x][y][num][max]=1; //满足条件 当前点到目标有1种方案
else
return dp[x][y][num][max]=0;//不满足条件 当前点到目标有0种方案
}
long long s=0;
if(x+1<=n){ //可以向下走
if (max<map[x][y])
s+=dfs(x+1,y,num+1,map[x][y]);//当前位置 拥有宝物的数量 拥有的宝物的最大值
s+=dfs(x+1,y,num,max); //当前位置 拥有宝物的数量 拥有的宝物的最大值
}
if(y+1<=m){ //可以向右走
if (max<map[x][y])
s+=dfs(x,y+1,num+1,map[x][y]);//当前位置 拥有宝物的数量 拥有的宝物的最大值
s+=dfs(x,y+1,num,max); //当前位置 拥有宝物的数量 拥有的宝物的最大值
}
return dp[x][y][num][max]=s%N;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for (int i = 1;i<=n;i++)//初始地宫
for (int j = 1; j <=m; j++)
scanf("%d",&map[i][j]);
memset(dp,-1,sizeof(dp));
dfs(1,1,0,-1);
printf("%d\n",dp[1][1][0][-1]);
return 0;
}
解决数组下标为-1,可以将所有值+1
#include <iostream>
#include <cstring>
using namespace std;
const int MOD = 1000000007;
int n, m, k;
int data[50][50];
long long ans;
long long cache[50][50][14][13];
void dfs(int x, int y, int max, int cnt) {
if (x == n || y == m || cnt > k)
return;
int cur = data[x][y];
if (x == n - 1 && y == m - 1)
{
if (cnt == k || (cnt == k - 1 && cur > max)) {
ans++;
if (ans > MOD)
ans %= MOD;
}
}
if (cur > max) {
dfs(x, y + 1, cur, cnt + 1);
dfs(x + 1, y, cur, cnt + 1);
}
dfs(x, y + 1, max, cnt);
dfs(x + 1, y, max, cnt);
}
long long dfs2(int x, int y, int max, int cnt) {
if (cache[x][y][max+1][cnt] != -1)
return cache[x][y][max+1][cnt];
long long ans = 0;
if (x == n || y == m || cnt > k)
return 0;
int cur = data[x][y];
if (x == n - 1 && y == m - 1)
{
if (cnt == k || (cnt == k - 1 && cur > max)) {
ans++;
if (ans > MOD)
ans %= MOD;
}
return ans;
}
if (cur > max) {
ans += dfs2(x, y + 1, cur, cnt + 1);
ans += dfs2(x + 1, y, cur, cnt + 1);
}
ans += dfs2(x, y + 1, max, cnt);
ans += dfs2(x + 1, y, max, cnt);
cache[x][y][max+1][cnt]=ans % MOD;
return cache[x][y][max+1][cnt];
}
int main(int argc, const char *argv[]) {
scanf("%d %d %d", &n, &m, &k);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
scanf("%d", &data[i][j]);
}
}
// dfs(0, 0, -1, 0);
// printf("%d\n", ans);
memset(cache,-1, sizeof(cache));
printf("%lli\n", dfs2(0, 0, -1, 0));
return 0;
}
地宫取宝|2014年蓝桥杯B组题解析第九题-fishers的更多相关文章
- 第十届蓝桥杯JavaB组省赛真题
试题 A: 组队 本题总分:5 分 [问题描述] 作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容. 每位球员担任 1 号位至 5 号位时的评分如下表所示. ...
- 啤酒和饮料|2014年蓝桥杯B组题解析第一题-fishers
啤酒和饮料|2014年第五届蓝桥杯B组题解析第一题-fishers 啤酒和饮料 啤酒每罐2.3元,饮料每罐1.9元.小明买了若干啤酒和饮料,一共花了82.3元. 我们还知道他买的啤酒比饮料的数量少,请 ...
- 第五届蓝桥杯JavaC组省赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.猜年龄 题目描述 小明带两个妹妹参加元宵灯会.别人问她们多大了,她们调皮地说:"我们俩的年龄之积是年龄之和的6倍" ...
- 第五届蓝桥杯JavaB组省赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.武功秘籍 小明到X山洞探险,捡到一本有破损的武功秘籍(2000多页!当然是伪造的).他注意到:书的第10页和第11页在同一张纸上,但第 ...
- 奇怪的分式|2014年蓝桥杯B组题解析第六题-fishers
奇怪的分式 上小学的时候,小明经常自己发明新算法.一次,老师出的题目是: 1/4 乘以 8/5 小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45 (参见图1.png) 老师刚想批评他,转念 ...
- 第十届蓝桥杯JavaC组省赛真题
试题 A: 求和 本题总分:5 分 [问题描述] 小明对数位中含有 2.0.1.9 的数字很感兴趣,在 1 到 40 中这样的数包 括 1.2.9.10 至 32.39 和 40,共 28 个,他们的 ...
- 第八届蓝桥杯JavaB组省赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.购物单 题目描述 小明刚刚找到工作,老板人很好,只是老板夫人很爱购物.老板忙的时候经常让小明帮忙到商场代为购物.小明很厌烦,但又不好推 ...
- 第九届蓝桥杯JavaC组省赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.哪天返回 题目描述 小明被不明势力劫持.后被扔到x星站再无问津.小明得知每天都有飞船飞往地球,但需要108元的船票,而他却身无分文. ...
- 第九届蓝桥杯JavaB组省赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.第几天 题目描述 2000年的1月1日,是那一年的第1天. 那么,2000年的5月4日,是那一年的第几天? 注意:需要提交的是一个整数 ...
随机推荐
- 完美解决onchange不能实时的监听
我们大家都知道onchange有时候很不好用,因为onchange事件是离开焦点后才会被触发,而不是实时去监听! 那么oninput()事件和onpropertychange()完美的解决了问题:(o ...
- CentOS VmwareTools安装
1. 虚拟机菜单栏--虚拟机--安装VMware tools 2. CentOS系统中弹出的VMware tools窗口中--右击VMwaretools.tar.gz--Extract到桌面 3.打开 ...
- [LeetCode] 121. Best Time to Buy and Sell Stock_Easy tag: Dynamic Programming
Say you have an array for which the ith element is the price of a given stock on day i. If you were ...
- C#webBrowser使用代理服务器的方法winform
其实在C#中使用webBrowser大家应该都会了,论坛也有很多相前的例子大家可以查询一下就知道了但是像直接使用浏览器一样设置代理 的方法可能很多人还不知道吧.这个其实是调用一个Dll文件进行设置的, ...
- 弱分类器的进化--Bagging、Boosting、Stacking
一般来说集成学习可以分为三大类: 用于减少方差的bagging 用于减少偏差的boosting 用于提升预测结果的stacking 一.Bagging(1996) 1.随机森林(1996) RF = ...
- jmeter 测试websocket接口(一)
jmeter 测试websocket接口时,需要对jmeter添加测试websocket的jar包. 下载地址: https://download.csdn.net/download/qq_14913 ...
- webdriver模拟鼠标悬浮
未经作者允许,禁止转载! 有时候会遇到这样的情况,鼠标停留在某一区域,不需要点击,悬浮在这一区域的上方就会显示该区域的下拉框,如下图 下面将鼠标停留在“日历”和“星座”这两个部分之间来回悬浮,下面是代 ...
- uva11107 后缀数组
题意给了n个串 然后计算 这些串中的子串在大于1/2的串中出现 求出这个串的最长长度. 将这些串用一个每出现的不同的字符拼起来 ,然后二分找lcp #include <iostream> ...
- 解决fiddler不能抓取eclipse发出接口请求的问题
使用eclipse执行接口时,发现在fiddler里面抓不到这些请求. 网上找了很多资料都是让在Eclipse 中设置:Windows > Preferences > Java > ...
- ActiveMQ 集群负载平衡
目前的架构: 负载均衡方案:========================================= 第二种方案呢,假设我们整个应用是个食堂,这个食堂里面有好多饭口,每个饭口有好多大爷大妈( ...