A question to take you to appreciate DFS-Record Search-DP

foreword

As mentioned in the title, DFS-Keeso-DP are the most commonly used methods in the Blue Bridge Cup competition. If you master them well, winning prizes will be easy. Let's take a look at 3 different ideas for this question through the 2014 underground palace treasure question.

Topic description

King X has an underground treasury. is a matrix of n × m lattices. Put one treasure in each cell. Each baby has a value sticker attached.

The entrance to the underground palace is in the upper left corner and the exit is in the lower right corner.

Xiao Ming was taken to the entrance of the underground palace, and the king asked him to walk only to the right or down .

When walking through a grid, if the value of the treasure in that grid is greater than that of any treasure in Xiao Ming's hand, Xiao Ming can pick it up (of course, he can also not take it).

When Xiaoming walks to the exit, if the treasures in his hand are exactly k, these treasures can be given to Xiaoming.

Please help Xiao Ming calculate how many different action plans he has to get these k treasures in a given situation.

enter description

Enter a line of 3 integers, separated by spaces: n , m , k ( 1 ≤ n , m ≤ 50 , 1 ≤ k ≤ 12 ) n,m,k (1≤n,m≤50,1≤k≤12)n,m,k(1n,m50,1k12)

Next there are n lines of data, each with m integers C i ( 0 ≤ C i ≤ 12 ) C_i\ (0 \leq C_i \leq 12)Ci (0Ci1 2 )
​ represents the value of the treasure on this grid.

output description

It is required to output an integer, indicating the number of action plans to take exactly kk babies. The number can be large, output it as 1 0 9 + 7 10^9+7109+7 modulo the result.

Input and output example

Example

enter

2 2 2
1 2
2 1

output

2

1. DFS


The dfs subscript will be
x, y from left to right, the number of treasures that have been taken so far, and the maximum value of the treasures taken.

#include <iostream>
using namespace std;
const int N = 60, MOD = 1e9 + 7;
int n, m, k;
int w[N][N];

int dfs(int x, int y, int u, int v) {
    
    
	if (x > n || y > m || u > k) return 0; // 判界
	if (x == n && y == m) {
    
     // 到达右下角
		// 已经拿了k个宝物或者加上右下角的最后一个宝物共k个
		if (u == k || u == k - 1 && w[x][y] > v) return 1;
		else return 0; 
	}
	if (w[x][y] > v) {
    
     // 当前位置的宝物价值比手里的大
		// 捡或不捡均可
		return dfs(x + 1, y, u, v) + dfs(x, y + 1, u, v)
		+ dfs(x+1, y, u+1, w[x][y]) + dfs(x, y+1, u+1, w[x][y]);
	} else {
    
    
		// 只有不捡
		return dfs(x + 1, y, u, v) + dfs(x, y + 1, u, v);
	}
}

int main() {
    
    
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> w[i][j];
	cout << dfs(1, 1, 0, -1) % MOD << endl;
	
	return 0;
}

2. Memorized search

Using an array to store the value of the procedure avoids repeated calculations, greatly reduces the time usage, and can pass the test point.
The most obvious difference is that the final answer of the memoized search is stored in the first array
and it demarcation in the process

#include <iostream>
#include <cstring>
using namespace std;
const int N = 60, MOD = 1e9 + 7;
int n, m, k;
int w[N][N];
int f[N][N][13][14];

int dfs(int x, int y, int u, int v) {
    
    
	if (f[x][y][u][v] != -1) return f[x][y][u][v];
	
	if (x == n && y == m) {
    
    
		if (u == k || u == k-1 && w[x][y] > v) return f[x][y][u][v] = 1;
		else return f[x][y][u][v] = 0;
	}
	
	long long s = 0;
	if (x + 1 <= n) {
    
    
		if (w[x][y] > v) s+= dfs(x+1, y, u+1, w[x][y]);
		s += dfs(x+1, y, u, v);
	} 
	
	if (y + 1 <= m) {
    
    
		if (w[x][y] > v) s+= dfs(x, y+1, u+1, w[x][y]);
		s += dfs(x, y+1, u, v);
	}
	
	return f[x][y][u][v] = s % MOD;
}

int main() {
    
    
	cin >> n >> m >> k;
	
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) {
    
    
			cin >> w[i][j];
			w[i][j]++;
		}
			
	
	memset(f, -1, sizeof f);
	dfs(1, 1, 0, 0); // 0 = -1
	
	cout << f[1][1][0][0] << endl;
	
	return 0;
}

3. DP

DP is the best solution to this problem. If you have figured out the first two methods, you can get DP with a little change. Since our usual DP is mostly one-dimensional to two-dimensional, it is inevitable to have doubts when reaching 4-dimensional, but we must still do it firmly.

  • Status representation f[i][j][u][v]: Indicates the number of legal solutions with u treasures and a maximum value of v when reaching the (i,j) position
  • State calculation: Due to the limitation of the topic, it can only go right or down, so we can divide the set into two categories according to this. When moving to the right, at the same time, the treasure in the position is larger than the one in the hand, and you can choose to take it or not take it, which is the sum of the number of plans; if the treasure is smaller than the maximum value in the hand, you can only choose not to take it. The same goes for the following.
#include <iostream>
using namespace std;
const int N = 60, MOD = 1e9 + 7;
int w[N][N];
int f[N][N][13][14];
int n, m, k;

int main() {
    
    
	scanf("%d%d%d", &n, &m, &k);
	
	for (int i = 1; i <= n; i++) 
		for (int j = 1; j <= m; j++) {
    
    
			cin >> w[i][j];
			w[i][j]++;
			// 宝贝的价值可以是0, 而-1不能用于索引,因此全部+1
		}
	
	// 初始化1,1位置上的值
	f[1][1][0][0] = 1; // 不取
	f[1][1][1][w[1][1]] = 1; // 取
	
	 
	for (int i = 1; i <= n; i++) {
    
    
		for (int j = 1; j <= m; j++) {
    
    
			if (i == 1 && j == 1) continue;
			for (int u = 0; u <= k; u++) {
    
    
				for (int v = 0; v < 13; v++) {
    
    
					int& val = f[i][j][u][v];
					// 不取当前位置,状态由左上方转移而来,加和
					val = (val + f[i-1][j][u][v]) % MOD;  
					val = (val + f[i][j-1][u][v]) % MOD;
					if (u > 0 && w[i][j] == v) {
    
    
						for (int c = 0; c < v; c++) {
    
    
							val = (val + f[i-1][j][u-1][c]) % MOD;  
							val = (val + f[i][j-1][u-1][c]) % MOD;
						}
					}
				}
			}
		}
	}
	// n,m,k都确定下来,枚举最后结果中所有的最大价值
	int res = 0;
	for (int i = 0; i < 13; i++) res = (res + f[n][m][k][i]) % MOD;
	cout << res << endl; 
	
	return 0;
}

Treasures from the Underground Palace-Original Title Link

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324110343&siteId=291194637