题目描述:
小强有一天想去郊区玩,但是路上会经过一片山路,山路可以看成是一个(行列)的网格,每个网格代表一个区域,山路崎岖不平,每一个区域都有一个会消耗的体力值。小强在走山路的时候,只能从一个区域走到相邻的4个(上下左右的网格)区域中的任意一个。每到一个区域,会消耗对应的体力值。小强初始位置在第一行上方,需要去到第行下方(可以在第一行任意区域作为起点,行任意区域作为终点)
小强想找一种走访,使得经过山路的总体力值最小。请你帮助小强找打这么一条路,并输出最小的总体力值消耗。
输入描述:
第一行包含两个数字,分别代表山路的行数和列数
接下来有行,每行个数字。第行列的数字,代表对应位置的区域的体力值。
示例1
输入
3 4
9 9 1 1
9 1 1 9
1 1 9 9
输出
4
示例2
输入
10 | 10 | 3 | 5 | 4 |
---|---|---|---|---|
9 | 1 | 2 | 1 | 9 |
6 | 19 | 33 | 1 | 9 |
1 | 2 | 3 | 4 | 5 |
3 | 7 | 10 | 90 | 20 |
输出
20
思考
- 把每列和的最小值记为,的值初始化为9999
- 把第一行第一列作为第一个位置,计算第一个位置与径直向下位置的和,记为。
- 计算第一个位置到第一个位置的左侧和左侧的径直下方的和是否小于,小于的话赋值给,并记录当前列。计算当前列从第一行到当前行的所有值的大小,和比较,小的话赋值给。继续向左侧比较。
- 同理,比较右侧。
- 遍历第一行的所有列,找出最小的消耗值。
代码:
#include <iostream>
using namespace std;
#include <vector>
////////////////////////////////////////////////
//void shortestPath(int startRow, int startCol, const int m, const int n, vector<vector<int> > a, int &firVal, int loss )
//1.startRow, startCol: 开始的座标点,从(0,0)开始
//2.m,n 数组的维度,m行n列
//3.a 动态二维数组
//4.firVal 列方向的损失值,初始化为列方向的最小值,结果保留在此
//5.loss 列方向损失值
////////////////////////////////////////////////
void shortestPath(int startRow, int startCol, const int m, const int n, vector<vector<int> > a, int &firVal, int loss )
{
/****************** 1. 找到第一行的损失 ************************/
int col = startCol; // 列下标
int row = startRow; // 行下标
int tempLoss = 0; // 临时保存的路程损失,赋值恨大,到时会纠正
loss = a[row][col]; //保存第一行的损失
//cout << "第一行的损失:" << loss << "\ta[0]" << a[0] << endl;
cout << "第一行路径:(" << row << "," << col << ")" << endl;
/****************** 2.继续往下一行,并判断左右是否有比往下小的路径 *************/
row ++; // 往下一行
int col_update = -1; // 存储每次列移动到哪里
while (row < m)
{
tempLoss = loss + a[row][col]; // 直接往下走的损失
//cout << "直接往下走的损失: " << endl;
//cout << "下一行路径:(" << row << "," << col << ")" << endl;
//判断左边是否有比它小的路径
int left_temp = 0; // 存储往左边走的大小
for (int i = col - 1; i >= 0; i--) // 当前列递减往左走判断
{
left_temp += a[row - 1][i]; // 连续增加左侧内容
//cout << "左边:(" << row << "," << i << ")" << endl;
if (left_temp + a[row][i] + loss < tempLoss) // 向左一步,向下一步
{
tempLoss = left_temp + a[row][i] + loss; // 更新tempLoss
col_update = i; // 将当前列存储到列中,以便下次更新列
// 判断当前列从第一行到当前行的值是否小于tempLoss,是的话更新
int sum = 0;
for (int j = 0; j <= row; j++)
{
sum += a[j][col_update];
} // end for
if (sum < tempLoss)
{
tempLoss = sum;
//cout << "\t左:更新所有loss " << endl;
}
//cout << "a[row - 1][i]: " << a[(row - 1) *n + i];
cout << "左更新: (" << row << "," << i << ")" << endl; // 输出当前位置
}// end if
} // end for left
//cout << "左:loss结果为:" << tempLoss << endl << endl;
// 判断右边是否有比它小的路径
int right_temp = 0;
for (int i = col; i < n; i++) // 下一列递加往右走判断
{
right_temp += a[(row - 1)][i]; // 连续增加右侧内容
//cout << "右:right_temp:" << right_temp << endl;
//cout << "右边:(" << row << "," << i << ")" << endl;
if (right_temp + a[row][i] + loss < tempLoss) // 向右一步,向下一步
{
tempLoss = right_temp + a[row][i] + loss;
col_update = i;
// 判断当前列从第一行到当前行的值是否小于tempLoss,是的话更新
int sum = 0;
for (int j = 0; j <= row; j++)
{
sum += a[j][col_update];
}
if (sum < tempLoss)
{
tempLoss = sum;
//cout << "右:更新所有loss:" << endl;
}
//cout << "a[row - 1][i]:" << a[(row - 1) * n + i];
cout << "右更新: (" << row << "," << i << ")" << endl; // 输出当前的位置
}
} // end for right
//cout << "右:loss结果为:" << tempLoss << endl;
// 每次都更新,loss每轮至少直接加下一行
loss = tempLoss; // 右侧找完赋值给loss
if (col_update != -1)
{
col = col_update; // 更新列
cout << "调用: (" << row << "," << col << ")" << endl << "************" << endl;
}
else
{
cout << "调用: (" << row << "," << col << ")" << endl << "************" << endl;
col = startCol;
}
row++; // 更新行
} // end while 搜寻结束
if (loss < firVal)
{
firVal = loss;
}
cout << "firVal: " << firVal << endl << endl;
// 是否到达最后一行?是的话和列的最小和比较,是否比它小?小的话返回,不小的话继续递归
if (startCol < n - 1)
{
shortestPath(startRow, startCol + 1, m, n, a, firVal, loss);
}
} // end shortestPath
int main()
{
int m = 0, n = 0; //行、列
cin >> m;
cin >> n;
vector<vector<int> > a(m, vector<int>(n)); // 动态申请二维数组
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
cin >> a[i][j];
}
}
//int a[3][4] = { 9, 9, 1, 1,
// 9, 1, 1, 9,
// 1, 1, 9, 9};
/*int a[3][3] = { 3, 1, 2,
1, 1, 0,
1, 3, 4
};*/
//int a[5][5] = { 10, 10, 3, 5, 4,
// 9, 1, 2, 1, 9,
// 6, 19, 33, 1, 9,
// 1, 2, 3, 4, 5,
// 3, 7, 10, 90, 20
// };
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
cout << a[i][j] << "\t";
}
cout << endl;
}
// 列下标求和的最小值赋值给sum
int sumLine = 9999;
int sumCol = 0;
for (int i = 0; i < n; i++)
{
sumCol = 0;
for (int j = 0; j < m; j++)
{
sumCol += a[j][i];
}
if (sumCol < sumLine)
{
sumLine = sumCol;
}
}
int loss = 0;
cout << "sumLine: " << sumLine << endl;
// sumLine作为最终的列损失值返回
shortestPath(0, 0, m, n, a, sumLine, loss);
cout << "所有的损失为:" << sumLine << endl;
system("pause");
return 0;
}
想法
大家如果有更好的想法可以一起讨论,让智慧的火花进行碰撞。