算法设计-方格取数

一、目的

  1. 正确应用动态规划求解方格取数问题。
  2. 对边界值测试结果。
  3. 正确分析算法时间复杂度。

二、实验内容与设计思想

1.设计思路

(1) 输入方格规模n,手动输入/自动生成n×n方格图
(2) 输出方格图
(3) 动态规划方格取数,输出最大取数结果

主要数据结构

结构名数据结构结构释义
maze二维数组储存方格图
dp思维数组dp[i][j][a][b]表示第一次取数到(i,j),第二次取数到(a,b)时,已经取得的数字和。

主要代码结构

三、实验使用环境

软件:Visual Studio 2022/1/4

平台:win10

实验步骤和调试过程

4.1 生成方格图

参数
输入:无
输出:方格图的规模

流程图
代码
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;
}
数据测试与结果:
迷宫大小迷宫模式数据结果
411 2 0 2 3 4 1 3 10 1 1 900 00 00 00 00 09 00 10 00 00 00 04 00 00 00 00
42/
02 72 07 81
31 15 28 21
27 56 30 31
69 24 87 33
81
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
82/
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
1212 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
122/
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 动态规划

参数
输入:/
输出:方格取数的解

流程图
代码
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 172576
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

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)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值