算法设计-方格取数

一、目的

  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
812 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 000 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 1400 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 801601
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 000
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 493641
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)
posted @ 2023-08-25 04:46  jijfurhg  阅读(75)  评论(0)    收藏  举报