题目
- 在一个 C 行 R 列的矩阵 M 中,其元素 M[i][j]可以滑翔到相邻的上下左右的四个元素中的一个(当然不能超出矩阵的边界),当且仅当相邻的元素比它要小,因为只能从高处滑翔到低处,每滑翔到一个元素,路径长度加 1,现在要求你编程计算该矩阵中最长的滑翔路径长度是多少。
要求输入矩阵的行列数和各元素的值,计算输出该矩阵中最长的滑翔路径长度。
【输入样例】
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
【输出样例】
25
算法设计思路
初始化矩阵
- 将矩阵的坐标和值存在数组s[][3]中,s[][0]存数值,s[][1]存x坐标,s[][2]存y坐标,设每个点的出口(step[][]数组)都为1。
按照值的大小从小到大进行排序
- 每位置都有对应的入口和出口,从小到大排列进行计算是可以使得留下仅有入口的方案且只需判断下个点的附近是否有标记过的点(即比它小的点且已经计算出此点的最长滑翔路径),按大小排序后先考虑图中点的下一个出口,得出各点的最长滑翔距离,依次向上类推将依据每个局部最优解推出下个状态的最优解,从而推出最优解。
- 如图(第一个),是一个滑翔矩阵视图,从大到小考虑该点的出口得出各点的最长出口 如图(第二个)(无出口标记为1)
设计初态
- Step[s[0][1]][s[0][2]]=1;即最小值无出口
设计状态方程
- 根据动态规划方程式测试数据应该得出结果如下,(为便于表示将step数组放置在括号中)
算法实现及其思路
变量的定义
- S[][3]中s[][0]存数值,s[][1],s[][2]中存分别存该点的坐标。Step[][]中存该点最大滑翔出路。
int s[N * N][3] = { 0 };
int step[N][N] = { 0 };
动态规划算法
- 根据已经排完顺序的坐标在step中进行遍历计算该点的出路多少(cmp函数),tempx,tempy分别是该点的坐标
int solve(int(*s)[3], int(*step)[N], int x, int y) {
int tempx, tempy;
for (int i = 0;i < x * y;i++) {
tempx = s[i][1];
tempy = s[i][2];//当前点所在位置
cmp(step, tempx, tempy);//选择当前点最优出口
}
return 1;
}
选择最优出路
- 比较附近四个点出路最多的并继承其步数,将最长出路存储在该点的step数组中
int cmp(int(*step)[N], int x, int y) {
int a, b, c, d, max1, max2, max3;
a = step[x + 1][y];
b = step[x - 1][y];
c = step[x][y - 1];
d = step[x][y + 1];//相邻的四个点
if (a > 0 || b > 0 || c > 0 || d > 0) {
max1 = max(a, b);
max2 = max(c, d);
max3 = max(max1, max2);//选出最优的四个路径
step[x][y] = max3 + 1;//以最优的路径作为出口
}
else
step[x][y] = 1;//无出口
return 1;
}
输出最优解及其坐标
- 依次比较step数组中的出路大小,输出最长的步数及其坐值标
void optimalpath(int(*step)[N], int x, int y) {
int max = step[1][1];
int tempx, tempy;
for (int i = 1;i < x + 1;i++) {
for (int j = 1;j < y + 1;j++) {
if (max < step[i][j])
{
max = step[i][j];
tempx = i;
tempy = j;
}
}
}
printf("最长滑翔%d,位置是(%d,%d)", max, tempx, tempy);
}
运行结果
完整代码
#include<stdio.h>
#define N 100
#pragma warning (disable:4996)
int initial(int(*s)[3], int x, int y) {
int i, j, k = 0;
printf("输入矩阵中的值:");
for (i = 1;i < x;i++) {
for (j = 1;j < y;j++) {
scanf("%d", &s[k][0]);//输入值
s[k][1] = i;
s[k][2] = j;//输入坐标
k++;
}
}
return 1;
}
int Sort(int(*arr)[3], int x, int y)//插入排序
{
for (int i = 1;i < x * y; i++) {
int j = i - 1;
int current = arr[i][0];
int currentx = arr[i][1];
int currenty = arr[i][2];
while (current < arr[j][0] && j >= 0) {
arr[j + 1][0] = arr[j][0];
arr[j + 1][1] = arr[j][1];
arr[j + 1][2] = arr[j][2];//交换坐标和值
j--;
}
arr[j + 1][0] = current;
arr[j + 1][1] = currentx;
arr[j + 1][2] = currenty;
}
return 1;
}//按值的大小进行排序
int max(int a, int b)
{
if (a > b)return a;
else return b;
}//两两比较选出最优路径
int cmp(int(*step)[N], int x, int y) {
int a, b, c, d, max1, max2, max3;
a = step[x + 1][y];
b = step[x - 1][y];
c = step[x][y - 1];
d = step[x][y + 1];//相邻的四个点
if (a > 0 || b > 0 || c > 0 || d > 0) {
max1 = max(a, b);
max2 = max(c, d);
max3 = max(max1, max2);//选出最优的四个路径
step[x][y] = max3 + 1;//以最优的路径作为出口
}
else
step[x][y] = 1;//无出口
return 1;
}
int solve(int(*s)[3], int(*step)[N], int x, int y) {
int tempx, tempy;
for (int i = 0;i < x * y;i++) {
tempx = s[i][1];
tempy = s[i][2];//当前点所在位置
cmp(step, tempx, tempy);//选择当前点最优出口
}
return 1;
}
void view(int(*s)[3], int x, int y) {
int k = 0;
printf("矩阵中数所在的位置\n");
for (int i = 0;i < x;i++) {
for (int j = 0;j < y;j++) {
printf("%d\t", s[k][0]);
k++;
}
printf("\n");
}
printf("\n");
}//将矩阵进行可视化
void solveview(int(*step)[N], int x, int y) {
for (int i = 1;i < x + 1;i++) {
for (int j = 1;j < y + 1;j++) {
printf("%d\t", step[i][j]);
}
printf("\n");
}
}//每个点最佳路径结果可视化
void optimalpath(int(*step)[N], int x, int y) {
int max = step[1][1];
int tempx, tempy;
for (int i = 1;i < x + 1;i++) {
for (int j = 1;j < y + 1;j++) {
if (max < step[i][j])
{
max = step[i][j];
tempx = i;
tempy = j;
}
}
}
printf("最长滑翔%d,位置是(%d,%d)", max, tempx, tempy);
}
int main() {
int x, y;
int s[N * N][3] = { 0 };
int step[N][N] = { 0 };
printf("请输入矩阵大小");
scanf("%d%d", &x, &y);
initial(s, x + 1, y + 1);//初始化
view(s, x, y);//矩阵可视化
Sort(s, x, y);//按数值进行大小排列
solve(s, step, x, y);//动态规划解决方法
printf("各个点可滑翔最大路径:\n");
solveview(step, x, y);
optimalpath(step, x, y);
return 0;
}