实验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********************/
}
测试结果
第一次写,动动小手,点个赞呗!朋友,谢谢。