编程笔试题之路径最短

题目描述:

小强有一天想去郊区玩,但是路上会经过一片山路,山路可以看成是一个nmn*m(nnmm列)的网格,每个网格代表一个区域,山路崎岖不平,每一个区域都有一个会消耗的体力值。小强在走山路的时候,只能从一个区域走到相邻的4个(上下左右的网格)区域中的任意一个。每到一个区域,会消耗对应的体力值。小强初始位置在第一行上方,需要去到第nn行下方(可以在第一行任意区域作为起点,nn行任意区域作为终点)

小强想找一种走访,使得经过山路的总体力值最小。请你帮助小强找打这么一条路,并输出最小的总体力值消耗。

输入描述:

第一行包含两个数字n,mn,m,分别代表山路的行数和列数

接下来有nn行,每行mm个数字。第iijj列的数字vijv_{ij},代表对应位置的区域的体力值。

示例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

思考

  1. 把每列和的最小值记为sumLinesumLinetempLosstempLoss的值初始化为9999
  2. 把第一行第一列作为第一个位置,计算第一个位置与径直向下位置的和,记为lossloss
  3. 计算第一个位置lossloss到第一个位置的左侧和左侧的径直下方的和是否小于tempLosstempLoss,小于的话赋值给tempLosstempLoss,并记录当前列。计算当前列从第一行到当前行的所有值的大小,和tempLosstempLoss比较,小的话赋值给tempLosstempLoss继续向左侧比较。
  4. 同理,比较右侧。
  5. 遍历第一行的所有列,找出最小的消耗值。

代码:

#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;
}

想法

大家如果有更好的想法可以一起讨论,让智慧的火花进行碰撞。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章