深度优先

这个家伙好懒,除了文章什么都没留下

0%

【算法】地宫取宝

历届试题 地宫取宝

时间限制:1.0s 内存限制:256.0MB

问题描述

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

类似迷宫问题,然后刚学了。只过了42%的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.util.Scanner;

public class Main {

static int n,m,k;
static int[][] map;
static int t=0;
public static void main(String[] args) {

Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
k=sc.nextInt();
map=new int[2+n][2+m];

for (int i = 0; i < 2+n; i++) {
for (int j = 0; j < 2+m; j++) {
if(i==0||j==0||i==1+n||j==1+m)//加一道墙
map[i][j]=-1;
else
map[i][j]=sc.nextInt();
}
}
dfs(1,1,-1,0);
dfs(1,1,map[1][1],1);
System.out.println(t);
}

//max当前拿到手中的最大个,count已经拿了多少个
private static void dfs(int i, int j,int max,int count) {

//System.out.println("("+i+","+j+"),count="+count+",max="+max);
//到达终点
if(i==n&&j==m){
if(count==k){
t=(t+1)%1000000007;
//System.out.println("OK!");
return;
}
}

if(!check(i,j)){
return;
}

//向右走
if(check(i,j+1)){
dfs(i,j+1,max,count);
//能不能拿起
if(map[i][j+1]>max){
dfs(i,j+1,map[i][j+1],count+1);//拿不拿起
}
}

//向下走
if(check(i+1,j)){
dfs(i+1,j,max,count);
if(map[i+1][j]>max){
dfs(i+1,j,map[i+1][j],count+1);
}
}

}

private static boolean check(int i, int j) {
if(map[i][j]!=-1)
return true;
else
return false;
}
}

优化后的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
 import java.util.Scanner;

/*
* 修改后的递归
*/
public class Main {

static int n,m,k;
static int[][] map;
static long[][][][] data;

public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
k=sc.nextInt();
map=new int[n+2][m+2];
data=new long[52][52][14][14];

for(int i=0;i<52;i++){
for(int ii=0;ii<52;ii++){
for(int iii=0;iii<14;iii++){
for(int iiii=0;iiii<14;iiii++){
data[i][ii][iii][iiii]=-1;
}
}
}
}

for (int i = 0; i < n+2; i++) {
for (int j = 0; j < m+2; j++) {
if(i==0||j==0||i==n+1||j==m+1)//加一道墙
map[i][j]=-1;
else
map[i][j]=sc.nextInt();
}
}

long total = dfs(1,1,-1,k); //从(1,1)开始,还可以拿k个,现在可拿">-1"的值
//这里写dfs(1,1,0,k)效果是一样的,为防止map中有质量为0的物品,写-1更稳妥
System.out.println(total%1000000007);
}

//max当前拿到手中的最大个,count还可以拿多少个
private static long dfs(int i, int j,int max,int count) {
//System.out.println("("+i+","+j+"),count="+count+",max="+max);

//无意义
if(!check(i, j, count)){
return 0;
}

//到达
if(i==n && j==m && count==0){
//System.out.println("成功!");
return data[i][j][max+1][count]=1;
}

if(i==n && j==m && count==1 && map[i][j]>max){
//System.out.println("成功!取最后一个");
return data[i][j][max+1][count]=1;
}

if(data[i][j][max+1][count]!=-1){
return data[i][j][max+1][count];
}
//如果现在的可以拿,则有四种情况:拿起,向右走;拿起,向下走;不拿,向右走;不拿向下走。
if(map[i][j]>max){
data[i][j][max+1][count]=dfs(i,j+1,map[i][j],count-1)+dfs(i+1,j,map[i][j],count-1)+dfs(i,j+1,max,count)+dfs(i+1,j,max,count);
return data[i][j][max+1][count];
}

//如果现在的不能拿,则有两种情况:不拿,向右走;不拿向下走。
if(map[i][j]<=max){
data[i][j][max+1][count]=dfs(i+1,j,max,count)+dfs(i,j+1,max,count);
return data[i][j][max+1][count];
}

return 0;
}

private static boolean check(int i, int j, int count) {
if(map[i][j]!=-1 && count>=0)
return true;
else
return false;
}
}