信息学奥赛一本通【动态规划】1261:【例9.5】城市交通路网

本文通过一个实例介绍了如何运用动态规划解决城市间交通路网的最短费用路径问题。分析指出,由于需要记录最短路径,需要采用从终点E到起点A的逆向动态规划。并提供了相应的思路和代码实现,强调了正确记录路径的重要性。

下图表示城市之间的交通路网,线段上的数字表示费用,单向通行由A->E。试用动态规划的最优化原理求出A->E的最省费用。

【输入】

第一行为城市的数量N;

后面是N*N的表示两个城市间费用组成的矩阵。

【输出】

第一行 A->E的最省费用。

第二行 A->E的最短路径。

【输入样例】

10
0  2  5  1  0  0  0  0  0  0
0  0  0  0 12 14  0  0  0  0
0  0  0  0  6 10  4  0  0  0
0  0  0  0 13 12 11  0  0  0
0  0  0  0  0  0  0  3  9  0
0  0  0  0  0  0  0  6  5  0
0  0  0  0  0  0  0  0 10  0
0  0  0  0  0  0  0  0  0  5
0  0  0  0  0  0  0  0  0  2
0  0  0  0  0  0  0  0  0  0

【输出样例】

minlong=19
1 3 5 8 10

思路分析:

动归的方向有两种,一种由A->E,另一种则由E->A

这题要使用哪一种?

关键在于输出中 “第二行 A->E的最短路径。”

如果从A出发,根本不肯能记录下最短路径,因为dp[i]只记录了由起点A到当前点i的最短距离,而无法判断其最终最短路径是哪一条

所以,我们只能使用逆推的方式

dp[i]记录了由i点到终点E的最短距离

再使用数组nextnode去记录每一次由i点到终点最短距离的路径

最后从点A出发 即i=1出发,输出nextnode[i]的值,且i的值更新为nextnode[i]的值

这样输出的nextnode[i]便是每一个点通往终点的最小值的下一个点。

代码如下:

#include<bits/stdc++.h>
#define N 1000005
using namespace std;
int mapp[1001][1001];//存储路径图,不知道n的范围,尽量大就好 
int dp[1001];
int n,ans;
int nextnode[1001];//后序节点 
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>mapp[i][j];
		}
	}
	dp[n]=0;//终点通往自己的路径长为0,动归模板的关键之一!!! 
	for(int i=1;i<n;i++){
		dp[i]=N;//初始化使得每个点i到终点的距离都为无限长,才能使比较时数据更新不会卡死 
	}
	for(int i=n-1;i>=1;i--){
		for(int j=i+1;j<=n;j++){
				if(mapp[i][j]!=0&&dp[j]+mapp[i][j]<dp[i]){//确定i点到终点的最短路径 
				dp[i]=dp[j]+mapp[i][j];
				nextnode[i]=j;//i点到终点的最短路径的下一节点 
			}
		}
	}
	cout<<"minlong="<<dp[1]<<endl;//最终输出由点1到终点的最短距离 
	int index=1;
	while(index){
		cout<<index<<" ";
		index=nextnode[index];//此处解析见文章 
	}
	return 0;
} 

 啧,第一遍打成了从A到E,结果第二行输出怎么都无法实现(泪崩

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值