一、目的
- 正确应用动态规划求解方格取数问题。
- 对边界值测试结果。
- 正确分析算法时间复杂度。
二、实验内容与设计思想
1.设计思路
(1) 输入方格规模n,手动输入/自动生成n×n方格图
(2) 输出方格图
(3) 动态规划方格取数,输出最大取数结果
主要数据结构
结构名 | 数据结构 | 结构释义 |
maze | 二维数组 | 储存方格图 |
dp | 思维数组 | dp[i][j][a][b]表示第一次取数到(i,j),第二次取数到(a,b)时,已经取得的数字和。 |
主要代码结构
![](http://akavjht.top/image/0023/image1.png)
三、实验使用环境
软件:Visual Studio 2022/1/4
平台:win10
实验步骤和调试过程
4.1 生成方格图
参数
输入:无
输出:方格图的规模
流程图
![](http://akavjht.top/image/0023/image2.png)
代码
int input()
{
cout << "请输入n作为迷宫的面积:";
int n;
cin >> n;
int mode = 0;
while (mode != 1 && mode != 2)
{
cout << "请选择迷宫模式:\n1、手动输入\n2、自动生成。\n";
cin >> mode;
}
if (mode == 1)
{
int x, y, v;
printf("请按照(x,y,数字)的方式输入。\n");
while (cin >> x >> y >> v)
{
if (x == 0 && y == 0 && v == 0)
break;
maze[x][y] = v;
}
}
else
{
srand((unsigned)time(NULL));
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
maze[i][j] = int(rand() % 100);
}
}
}
return n;
}
数据测试与结果:
迷宫大小 | 迷宫模式 | 数据 | 结果 |
4 | 1 | 1 2 0 2 3 4 1 3 10 1 1 9 | 00 00 00 00 00 09 00 10 00 00 00 04 00 00 00 00 |
4 | 2 | / | 02 72 07 81 31 15 28 21 27 56 30 31 69 24 87 33 |
8 | 1 | 2 3 13 2 6 6 3 5 7 4 4 14 5 2 21 5 6 4 6 3 15 7 2 14 0 0 0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 00 06 00 00 00 00 00 00 07 00 00 00 00 00 00 14 00 00 00 00 00 21 00 00 00 04 00 00 00 00 15 00 00 00 00 00 00 14 00 00 00 00 00 |
8 | 2 | / | 60 28 53 39 82 47 68 43 23 79 46 11 69 64 64 86 41 51 60 79 21 35 40 39 56 24 37 63 34 49 48 96 40 04 64 90 27 46 92 06 40 18 90 71 39 06 72 67 36 04 01 99 89 07 76 04 82 27 57 48 21 32 48 81 |
12 | 1 | 2 913 2 106 3 47 4 4 14 5 2 21 5 6 4 6 3 15 112 14 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 06 00 00 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 00 00 21 00 00 00 04 00 00 00 00 00 00 00 00 15 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 00 00 |
12 | 2 | / | 97 96 80 89 42 18 85 66 43 02 41 08 37 47 00 18 29 62 28 94 69 21 63 57 03 41 54 79 06 03 41 35 17 69 96 74 43 13 17 06 71 52 39 19 93 80 67 89 25 14 25 91 32 70 17 39 40 15 46 94 47 08 75 62 07 71 96 82 80 27 55 76 19 96 48 72 26 54 30 21 59 28 31 02 06 41 45 11 97 84 01 28 22 80 33 33 95 78 13 74 93 62 47 57 39 08 80 58 96 79 12 02 32 58 61 99 26 79 71 26 14 16 00 30 70 24 62 89 22 98 83 69 16 04 97 04 60 23 82 23 92 16 59 23 |
4.2 输出方格图
参数
输入:方格图的规模
输出:无
代码
void printMaze(int n)
{
cout << "迷宫已经生成完毕\n";
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%2d ", maze[i][j]);
}
printf("\n");
}
}
4.3 动态规划
参数
输入:/
输出:方格取数的解
流程图
![](http://akavjht.top/image/0023/image3.png)
代码
void DynamicProgramming(int n)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
for (int l = 1; l <= n; l++)
{
int maze1 = max(dp[i - 1][j][k - 1][l], dp[i - 1][j][k][l - 1]);
int maze2 = max(dp[i][j - 1][k - 1][l], dp[i][j - 1][k][l - 1]);
dp[i][j][k][l] = max(maze1, maze2) + maze[i][j];
//如果两个走的不相同,加上maze[k][l]的值
if (i != k && j != l)
dp[i][j][k][l] += maze[k][l];
}
}
}
}
cout << "最终答案是:" << dp[n][n][n][n] << endl;//最终答案
}
一个四重循环枚举两条路分别走到的位置。
maze[i][j]表示(i,j)格上的值,dp[i][j][h][k]表示第一条路走到(i,j),第二条路走到(h,k)时的最优解。
使用四重循环令i,j,h,k都从[1,n]对dp进行更新,最后的dp[n][n]即是答案。
测试数据与结果:
方格图 | 取数结果 |
21 25 65 62 45 27 39 13 29 69 91 21 90 68 31 25 90 35 47 90 75 92 11 57 91 16 54 06 17 59 97 89 36 18 37 56 75 84 73 65 09 64 80 10 86 59 53 30 73 85 71 25 51 98 79 78 51 37 16 44 28 17 11 80 | 1601 |
06 72 81 16 80 50 27 08 46 60 13 66 77 88 03 63 30 39 78 39 66 80 80 97 52 33 21 90 90 83 86 88 95 86 67 89 89 16 56 92 14 30 39 49 19 52 85 20 19 82 94 03 29 50 58 71 17 09 01 19 00 96 93 45 18 24 67 36 52 57 00 23 06 62 08 74 42 21 80 14 26 76 67 56 90 77 78 52 58 74 10 48 42 72 74 38 58 65 65 37 85 19 22 65 97 23 46 64 33 54 08 13 78 34 23 59 70 24 74 37 09 09 94 28 93 39 31 52 89 85 88 28 13 89 24 77 52 09 56 30 57 84 21 17 | 2576 |
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 0 |
78 88 85 23 63 25 32 13 62 10 13 72 33 59 37 98 44 47 90 57 64 57 43 44 77 82 69 77 57 02 89 82 04 74 47 05 89 97 29 85 12 89 41 03 34 04 78 08 02 56 38 05 85 40 59 93 85 48 55 18 37 95 26 59 24 30 30 68 03 52 47 02 88 40 54 21 80 43 50 83 75 15 29 62 71 18 60 13 38 71 34 03 96 62 11 33 92 26 24 17 45 52 65 94 61 33 65 78 17 68 25 57 20 57 91 81 88 45 41 39 60 71 63 11 85 74 50 62 27 60 17 19 44 43 31 32 38 06 78 83 36 26 18 45 19 85 06 08 22 95 44 47 40 39 30 82 71 57 63 49 13 37 54 34 06 26 39 69 93 72 24 75 44 54 86 36 89 41 76 53 71 93 42 30 64 73 70 89 04 21 11 07 33 33 35 87 57 53 87 68 61 75 20 22 35 04 24 36 82 99 33 52 85 87 25 55 53 35 51 95 47 95 25 62 37 60 51 25 35 32 79 33 46 99 77 52 12 84 37 24 79 40 30 03 94 08 17 02 60 94 94 92 16 31 15 49 | 3641 |
21 25 65 62 45 27 39 13 29 69 91 21 90 68 31 25 90 35 47 90 75 92 11 57 91 16 54 06 17 59 97 89 36 18 37 56 75 84 73 65 09 64 80 10 86 59 53 30 73 85 71 25 51 98 79 78 51 37 16 44 28 17 11 80 | |
06 72 81 16 80 50 27 08 46 60 13 66 77 88 03 63 30 39 78 39 66 80 80 97 52 33 21 90 90 83 86 88 95 86 67 89 89 16 56 92 14 30 39 49 19 52 85 20 19 82 94 03 29 50 58 71 17 09 01 19 00 96 93 45 18 24 67 36 52 57 00 23 06 62 08 74 42 21 80 14 26 76 67 56 90 77 78 52 58 74 10 48 42 72 74 38 58 65 65 37 85 19 22 65 97 23 46 64 33 54 08 13 78 34 23 59 70 24 74 37 09 09 94 28 93 39 31 52 89 85 88 28 13 89 24 77 52 09 56 30 57 84 21 17 | |
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
78 88 85 23 63 25 32 13 62 10 13 72 33 59 37 98 44 47 90 57 64 57 43 44 77 82 69 77 57 02 89 82 04 74 47 05 89 97 29 85 12 89 41 03 34 04 78 08 02 56 38 05 85 40 59 93 85 48 55 18 37 95 26 59 24 30 30 68 03 52 47 02 88 40 54 21 80 43 50 83 75 15 29 62 71 18 60 13 38 71 34 03 96 62 11 33 92 26 24 17 45 52 65 94 61 33 65 78 17 68 25 57 20 57 91 81 88 45 41 39 60 71 63 11 85 74 50 62 27 60 17 19 44 43 31 32 38 06 78 83 36 26 18 45 19 85 06 08 22 95 44 47 40 39 30 82 71 57 63 49 13 37 54 34 06 26 39 69 93 72 24 75 44 54 86 36 89 41 76 53 71 93 42 30 64 73 70 89 04 21 11 07 33 33 35 87 57 53 87 68 61 75 20 22 35 04 24 36 82 99 33 52 85 87 25 55 53 35 51 95 47 95 25 62 37 60 51 25 35 32 79 33 46 99 77 52 12 84 37 24 79 40 30 03 94 08 17 02 60 94 94 92 16 31 15 49 |
4.4 时间复杂度
-
生成方格图:O(n2)
无好坏情况之分,方格图是n×n个数字组成的,需要生成n×n个随机数。 -
动态规划:O(n4)
最坏情况=最好情况:O(n4)
因为有四重循环,每一重循环都是1~n。所以是n4。
![](http://akavjht.top/image/0023/image4.png)
200次方格取数时间图
4.5 空间复杂度
-
生成方格图:O(n2)
方格图是n×n个数字组成的,所以需要n×n的二维数组储存。 -
动态规划:O(n4)
最坏情况=最好情况:O(n4)
因为有两次取数,相当于两个人同时走,所以需要n×n×n×n的四维数组来储存,所以是n4。
五、附录
方格取数
#include<bits/stdc++.h>
using namespace std;
int maze[15][15];
int dp[15][15][15][15];
int input()
{
cout << "请输入n作为迷宫的面积:";
int n;
cin >> n;
int mode = 0;
while (mode != 1 && mode != 2)
{
cout << "请选择迷宫模式:\n1、手动输入\n2、自动生成。\n";
cin >> mode;
}
if (mode == 1)
{
int x, y, v;
printf("请按照(x,y,数字)的方式输入。\n");
while (cin >> x >> y >> v)
{
if (x == 0 && y == 0 && v == 0)
break;
maze[x][y] = v;
}
}
else
{
srand((unsigned)time(NULL));
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
maze[i][j] = int(rand() % 100);
}
}
}
return n;
}
void printMaze(int n)
{
cout << "迷宫已经生成完毕\n";
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%2d ", maze[i][j]);
}
printf("\n");
}
}
void DynamicProgramming(int n)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
for (int l = 1; l <= n; l++)
{
int maze1 = max(dp[i - 1][j][k - 1][l], dp[i - 1][j][k][l - 1]);
int maze2 = max(dp[i][j - 1][k - 1][l], dp[i][j - 1][k][l - 1]);
dp[i][j][k][l] = max(maze1, maze2) + maze[i][j];
//如果两个走的不相同,加上maze[k][l]的值
if (i != k && j != l)
dp[i][j][k][l] += maze[k][l];
}
}
}
}
cout << "最终答案是:" << dp[n][n][n][n] << endl;//最终答案
}
int main()
{
int n = input();
printMaze(n);
DynamicProgramming(n);
}
打印200方格取数时间
#include<bits/stdc++.h>
using namespace std;
int maze[100][100];
int dp[100][100][100][100];
int num[200];
void readfile_byword()
{
string filename = "D:\\Desktop\\3.txt";
ifstream OpenFile(filename);
if (OpenFile.fail())
{
cout << "打开文件错误!" << endl;
exit(0);
}
string str;
stringstream ss;
for (int i = 0; i < 200; i++)
{
OpenFile >> str;
ss << str;
ss >> num[i];
ss.clear();
}
OpenFile.close();
system("pause");
}
int input(int n)
{
printf("%d ", n);
int mode = 2;
if (mode == 1)
{
int x, y, v;
printf("请按照(x,y,数字)的方式输入。\n");
while (cin >> x >> y >> v)
{
if (x == 0 && y == 0 && v == 0)
break;
maze[x][y] = v;
}
}
else
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
maze[i][j] = int(rand() % 100);
}
}
}
return n;
}
void printMaze(int n)
{
cout << "迷宫已经生成完毕\n";
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%02d ", maze[i][j]);
}
printf("\n");
}
}
void DynamicProgramming(int n)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
for (int k = 1; k <= n; k++)
{
for (int l = 1; l <= n; l++)
{
int maze1 = max(dp[i - 1][j][k - 1][l], dp[i - 1][j][k][l - 1]);
int maze2 = max(dp[i][j - 1][k - 1][l], dp[i][j - 1][k][l - 1]);
dp[i][j][k][l] = max(maze1, maze2) + maze[i][j];
//如果两个走的不相同,加上maze[k][l]的值
if (i != k && j != l)
dp[i][j][k][l] += maze[k][l];
}
}
}
}
//cout << "最终答案是:" << dp[n][n][n][n] << endl;//最终答案
}
int main()
{
readfile_byword();
for (int i = 0; i <200; i++)
{
clock_t start, finish;
start = clock();
int n = input(num[i]);
//printMaze(n);
DynamicProgramming(n);
finish = clock();
double time = (double)(finish - start) / CLOCKS_PER_SEC; //单位换算成秒
cout << time << endl;
}
}
画散点图
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/9/23 17:26
# @Author : Fw_022
import numpy as np
import matplotlib.pyplot as plt
import random
def draw(x, y):
area = 200
colors = [random.random() for i in range(len(x))]
plt.figure(figsize=(20, 10))
plt.style.use('seaborn-whitegrid')
plt.scatter(x, y, s=area, c=colors, alpha=0.4, label='Duration Time', cmap='viridis')
# 颜色条:viridis,RdBu
plt.legend(fontsize=30)
plt.xlabel("n", fontsize=30)
plt.ylabel('Time', fontsize=30)
plt.xticks(fontsize=30, color='#000000')
plt.yticks(fontsize=30, color='#000000')
# plt.xticks([]) # 不显示x轴刻度值
# plt.tick_params(labelsize=20) 刻度值字体大小
plt.tick_params(pad=5) # 刻度距离坐标轴的距离调整
plt.colorbar() # 显示颜色对比条
plt.savefig(r"D:\Desktop\a.png", bbox_inches='tight', dpi=1000)
plt.show()
if __name__ == "__main__":
path = r"D:\Desktop\time.txt"
data = open(path).readlines()
x, y = [], []
for i in data:
a, b = i.split(' ')
x.append(int(a))
y.append(float(b))
draw(x, y)