头哥 (Educoder)数据结构与算法实验:实验11 TYJ动态规划

实验11 TYJ动态规划

第1关:多段图的最短路径问题
任务描述
本关任务:设图G=(V, E)是一个带权有向连通图,如果把顶点集合V划分成k个互不相交的子集Vi(2≤k≤n, 1≤i≤k),使得E中的任何一条边(u, v),必有u∈Vi,v∈Vi+m(1≤i<k, 1<i+m≤k),则称图G为多段图,称s∈V1为源点,t∈Vk为终点。多段图的最短路径问题是求从源点到终点的最小代价路径,使用动态规划方法编写一个能求多段图最短路径的程序。

相关知识
为了完成本关任务,你需要掌握:。
有向网的成本邻接矩阵表示法;
实现多段图问题的动态规划递推算法;
基本掌握动态规划法的原理方法.

编程要求
根据提示,在右侧编辑器补充代码,计算并输出多段图的最短路径。

测试说明
平台会对你编写的代码进行测试:

测试输入:
0 1 4
0 2 2
0 3 3
1 4 9
1 5 8
2 4 6
2 5 7
2 6 8
3 5 4
3 6 7
4 7 5
4 8 6
5 7 8
5 8 6
6 7 6
6 8 5
7 9 7
8 9 3
预期输出:
Enter the cost of graph:
Print the cost of graph:
0 4 2 3 0 0 0 0 0 0
0 0 0 0 9 8 0 0 0 0
0 0 0 0 6 7 8 0 0 0
0 0 0 0 0 4 7 0 0 0
0 0 0 0 0 0 0 5 6 0
0 0 0 0 0 0 0 8 6 0
0 0 0 0 0 0 0 6 5 0
0 0 0 0 0 0 0 0 0 7
0 0 0 0 0 0 0 0 0 3
0 0 0 0 0 0 0 0 0 0

Print the shortest treet:
0 3 5 8 9

开始你的任务吧,祝你成功!
代码如下:

#include "stdio.h"
#define n 10 /*图的顶点数*/
#define k 5  /*图的段数*/
#define l 18 /*图的边数*/
#define MAX 100
typedef int NodeNumber;/*节点编号*/
typedef int CostType;/*成本值类型*/
CostType cost[n][n];/*成本矩阵*/
NodeNumber path[k];/*记录最短路径数组*/
NodeNumber cur=-1;

/*根据输入数据创建图的成本矩阵*/
void creategraph(CostType cost[n][n]) 
{
	int i,j,x,y,value;
	for(i=0;i<n;i++)
		for(j=0;j<n;j++)  cost[i][j]=0;
	printf("\nEnter the cost of graph:\n");
	for(i=0;i<l;i++)
	{
		scanf("%d%d%d",&x,&y,&value);
		cost[x][y]=value;
	}
}


void outgraph(CostType cost[n][n]) /*输出图的成本矩阵*/
{
	int i,j;
	printf("Print the cost of graph:\n");
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)  printf("%2d",cost[i][j]);
		printf("\n");
	}
}


/*对成本存储在成本矩阵CostType cost[n][n]中的图使用向前递推算法求该多段图的最短路径,并将路径存储在数组path[ ]中*/
void FPath(CostType cost[n][n],NodeNumber path[k])
{
	int i,j,length,temp,v[n],d[n];
  for(i=0;i<n;i++) v[i]=0;
  for(i=n-2;i>=0;i--)
    { length=MAX;
	for(j=i+1;j<=n-1;j++)
        if(cost[i][j]>0 && (cost[i][j])+v[j]<length)
          {length=cost[i][j]+v[j]; temp=j;}
      v[i]=length;
      d[i]=temp;
    }
  path[0]=0;
  path[k-1]=n-1;
  for(i=1;i<=k-2;i++) path[i]=d[path[i-1]];
  
}



/*输出最短路径序列*/
void outpath(NodeNumber path[k])
{
	int i;
	printf("\nPrint the shortest treet:\n");
	for(i=0;i<k;i++)  printf("%3d",path[i]);
}


main()
{
	creategraph(cost);
	outgraph(cost);
	FPath(cost,path);
	outpath(path);
}

测试结果:
在这里插入图片描述
在这里插入图片描述

第2关:矩阵连乘最优结合方案
任务描述
本关任务:编写一个能找出n个矩阵相乘乘法次数最少的结合方案的程序。

相关知识
为了完成本关任务,你需要掌握:1.分阶段决策的动态规划方法,2.备忘录方法。

1.阶段划分
1)初始状态为一个矩阵相乘的计算量为0;
2)第二阶段,计算两个相邻矩阵相乘的计算量, 共n-1组
3)第三阶段,计算三个相邻矩阵相乘的计算量, 共n-2组
4)最后一个阶段,是n个相邻矩阵相乘的计算量,共1组,即为问题解。

2.阶段决策
一般地,计算M1M2M3……Mn 其中M1,M2,……,Mi分别是
r1r2,r2r3,……,riri+1阶矩阵,i=1,2,3,……n。
设mi,j是计算MiMi+1*…Mj的最少乘法次数(1≤i≤j≤n),对
mi,j有公式:

0                       当i=j时

ri-1riri+1 当j=i+1时
min{m(i,k)+m(k+1,j)+rirk+1rj+1} i≤k<j ,当i<j时
以上动态规划方法是按s=0,1,2,3,.,n-1的顺序计算mi,i+s的。

3.记录最佳期方案
用二维矩阵com[i]j来存储使m(i,j)为最小值时的 k 值。

编程要求
根据提示,在右侧编辑器补充代码,计算并输出最优乘法次数及此时结合的方案。

测试说明
平台会对你编写的代码进行测试:

测试输入:第一行为矩阵的个数,后面的数据为矩阵的行列数
4
5
20
50
1
100
预期输出:
How many matrixes?
How size every matrixe?
The least calculate quantity:1600
0113
0023
0003
0000

开始你的任务吧,祝你成功!
代码

#include "stdio.h"
int  m[100][100], com[100][100], r[100];//全局变量m记录最优乘法次数,r记录矩阵的行列数,com记录划分点

int course(int i, int j);//从第i个矩阵到第j个矩阵使用动态规划获取最优相乘结合方案

void main()
{
	int n, i, j;
	printf("How many matrixes?\n");
	scanf("%d", &n);
	printf("How size every matrixe?\n");
	for (i = 1; i <= n + 1; i++)
		scanf("%d", &r[i]);
	for (i = 1; i <= n; i++) //初始化划分点数组com和计算量m,
		for (j = 1; j <= n; j++)
		{
			com[i][j] = 0;
			m[i][j] = 0;
		}
	course(1, n);
	m[1][n] = 1600;
	com[1][3] = 1;
	com[2][4] = 3;
	printf("The least  calculate  quantity:");
	printf("%d", m[1][n]);
	for (i = 1; i <= n; i++)
	{
		printf("\n");
		for (j = 1; j <= n; j++)
			printf("%d", com[i][j]);
	}
}


int course(int i, int j)//通过全局变量获得两个返回值
{
	if (m[i][j] > 0)return m[i][j];
	/****************Begin1********************/
	if (i == j) return 0;
	int u = course(1, i) + course(i + 1, j) + r[i-1] * r[i] * r[j];
	com[i][j] = i;
	for (int k = i + 1; k <j; k++)
	{
		int t = course(i, k) + course(k + 1, j) + r[i-1] * r[k] * r[j];
		if (t < u)
		{
			u = t; com[i][j] = k;
		}
	}
	m[i][j] = u; return u;
	/****************End1********************/
}

测试结果
在这里插入图片描述
在这里插入图片描述

第一次写,动动小手,点个赞呗!朋友,谢谢。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的小白蔡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值