题目
一个m * n的列表中,每格上有一个数,找到从左上角到右下角的路径,经过所有格的数之和最少。
注意,每次位移只能向右或向下。
结果
下面path里的编号,是指从上到下,从左到右的格子编号。
1 | 3 | 1 |
---|---|---|
1 | 5 | 1 |
4 | 2 | 1 |
the path is: 0 1 2 5 8
the values is: 1 3 1 1 1
total: 7
1 | 2 | 3 |
---|---|---|
4 | 5 | 6 |
the path is: 0 1 2 5
the values is: 1 2 3 6
total: 12
1 | 1 | 4 |
---|---|---|
3 | 5 | 2 |
1 | 1 | 1 |
the path is: 0 3 6 7 8
the values is: 1 3 1 1 1
total: 7
代码
这里算法很简单,就是普通的深度优先递归。
为生成路径信息时,我之前一直认为每递归一条路径时,要返回其完整路径。但实际上这很愚蠢,因为这会生成非常多的路径信息, 数目大概是 ∑ k = 1 n + m − 2 2 k \displaystyle \sum_{k=1}^{n+m-2} 2^k k=1∑n+m−22k。其实只要让每个格子,标记下一个最小路径的位置即可,大小也就m*n的大小。
#include <iostream>
class EGrid {
public:
EGrid(int* data, int row, int col) :col_count(col), row_count(row){
const int t = row * col;
grid_data = new int[t];
next_min_index = new int[t];
step_count = row + col - 1;
result = new int[step_count];
memcpy(grid_data, data, sizeof(int) * t);
total = 0;
}
~EGrid() {
delete[] grid_data;
grid_data = nullptr;
delete[] result;
result = nullptr;
delete[] next_min_index;
next_min_index = nullptr;
}
int _find_min_path(int cur_row, int cur_col) {
if (cur_row >= row_count || cur_col >= col_count)
return -1;
const int cur_index = cur_row * col_count + cur_col;
int cur_value = grid_data[cur_index];
if (cur_row == row_count - 1 && cur_col == col_count - 1)
return cur_value;
const int r1[] = { cur_row + 1, cur_col };
const int r2[] = { cur_row, cur_col+1 };
int res1 = _find_min_path(r1[0], r1[1]);
int res2 = _find_min_path(r2[0], r2[1]);
bool is_res_1 = true;
if (res1 == -1 && res2 == -1)
return -1;
if (res1 == -1 && res2 != -1)
is_res_1 = false;
else if (res1 != -1 && res2 == -1)
is_res_1 = true;
else
is_res_1 = (res1 < res2);
const int* rs = (is_res_1 ? r1 : r2);
const int next_index = rs[0] * col_count + rs[1];
next_min_index[cur_index] = next_index;
const int res = is_res_1 ? res1 : res2;
if (next_index == 4)
int k = 22434;
return res + cur_value;
}
const int* find_min_path() {
result[0] = 0;
total = 0;
total = this->_find_min_path(0, 0);
for (int i = 1; i < step_count; ++i) {
result[i] = next_min_index[result[i - 1]];
}
return this->result;
}
void output_res() {
//int total = 0;
std::cout << std::endl;
for (int j = 0; j < col_count; ++j) {
std::cout << "|" << grid_data[j] ;
}
std::cout << "|" << std::endl;
for (int j = 0; j < col_count; ++j) {
std::cout << "|:--:";// << grid_data[j];
}
std::cout << "|"<< std::endl;
for (int i = 1; i < row_count; ++i) {
int row_i = i * col_count;
for (int j = 0; j < col_count; ++j) {
std::cout << "|" << grid_data[row_i + j];
}
std::cout << "|"<< std::endl;
}
std::cout << "the path is:";
for (int i = 0; i < step_count; ++i) {
std::cout << " " << result[i];
}
std::cout << std::endl << "the values is:";
for (int i = 0; i < step_count; ++i) {
const int index = result[i];
const int v = this->grid_data[index];
std::cout << " " << v;
}
std::cout << std::endl << "total: " << total;
}
int col_count;
int row_count;
int step_count;
int* grid_data;
int* next_min_index;
int* result;
int* temp_path;
int* temp_path2;
int total;
};
void find_min_path() {
{
int data[] = {
1, 3, 1,
1, 5, 1,
4, 2, 1
};
EGrid g(data, 3, 3);
g.find_min_path();
g.output_res();
}
{
int data[] = {
1, 2, 3,
4, 5, 6
};
EGrid g(data, 2, 3);
g.find_min_path();
g.output_res();
}
{
int data[] = {
1, 1, 4,
3, 5, 2,
1, 1, 1
};
EGrid g(data, 3, 3);
g.find_min_path();
g.output_res();
}
}