備賽重要, 先放代碼, 題解有時間再寫.
#include<stdio.h>
#include<string.h>
#define MOD 1000000007
int N = 0;
int M = 0;
int K = 0;
// 存放輸入地圖
int num[51][51] = {0};
// 存放路徑結果
unsigned long long count_array[51][51] = {0};
// 開一個bool 4維數組
// 前兩維表示x, y
// 後面一個表示k值, 用來減少搜索,
// 如果k已經存在 那麼不用繼續搜索了, 直接+1種情況,
// 如果不存在就記錄, 並且繼續搜索
// 最後面一個是當前k值下拿到的最大寶物數
int cache[51][51][13][13] = {0};
unsigned long long count = 0;
// 直接搜索
void dfs_1(int n, int x, int y, int max){
if(x >= M || y >= N) return;
if(num[y][x] > max && n < K){// 可以拿就拿
// 剪枝
if(n + 1 == K){ // 如果拿起後就夠了 直接加上次數 防止不必要的搜索了
count += count_array[y][x];
count %= MOD;
}else{
int temp = max;
max = num[y][x];
dfs_1(n + 1, x + 1, y, max);
dfs_1(n + 1, x, y + 1, max);
max = temp;
}
}
// 不可以拿, 或者可以拿卻不拿
dfs_1(n, x + 1, y, max);
dfs_1(n, x, y + 1, max);
}
// 記憶式搜索
long long dfs_4(int n, int x, int y, int max){
// 限定邊界
if(x >= M || y >= N) return 0;
// 查看錶, 如果表已經有數據, 表示正在遍歷一個重複的節點, 直接返回結果
if(cache[y][x][n][max] != 0){
return cache[y][x][n][max];
}
// 注: 爲當前節點所有子節點結果之和
// 取到和 之後,然後存放進表, 如果以後表裏面有數據, 那麼就可以直接使用
long long sum = 0;
if(num[y][x] > max && n < K){// 可以拿就拿
if(n + 1 == K){ // 如果拿起後就夠了 直接加上次數 防止不必要的搜索了
// 這裏是唯一的出口
sum += count_array[y][x];
}else{
int temp = max;
max = num[y][x];
sum += dfs_4(n + 1, x + 1, y, max);
sum %= MOD;
sum += dfs_4(n + 1, x, y + 1, max);
sum %= MOD;
max = temp;
}
}
// 不可以拿, 或者可以拿卻不拿
sum += dfs_4(n, x + 1, y, max);
sum %= MOD;
sum += dfs_4(n, x, y + 1, max);
cache[y][x][n][max] = sum % MOD;
return sum % MOD;
}
int main(){
scanf("%d %d %d", &N, &M, &K);
for(int i= 0; i < N; i++){
for(int j = 0; j < M; j++){
scanf("%d", &num[i][j]);
}
}// 輸入結束
// 計算次數矩陣
// 用來剪掉 已經找到k件寶物的結果, 使其不再繼續搜索, 直接得出答案
count_array[N - 1][M] = 1;
for(int i = N - 1; i >= 0; --i){
for(int j = M - 1; j >= 0; --j){
count_array[i][j] = count_array[i + 1][j] + count_array[i][j + 1];
count_array[i][j] %= MOD;
}
}
dfs_1(0, 0, 0, 0);
printf("直接搜索結果: %lld\n", count);
// 計算答案
long long ans = dfs_4(0, 0, 0, 0);
printf("記憶搜索結果: %lld\n", ans);
return 0;
}