洛谷 P1397 租用游艇

题目链接:租用游艇 - 洛谷

 

题目描述

长江游艇俱乐部在长江上设置了 nn 个游艇出租站 1,2,⋯ ,n1,2,⋯,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站 ii 到游艇出租站 jj 之间的租金为 r(i,j)r(i,j)(1≤i<j≤n1≤i<j≤n)。试设计一个算法,计算出从游艇出租站 11 到游艇出租站 nn 所需的最少租金。

输入格式

第一行中有一个正整数 nn,表示有 nn 个游艇出租站。接下来的 n−1n−1 行是一个半矩阵 r(i,j)r(i,j)(1≤i<j≤n1≤i<j≤n)。

输出格式

输出计算出的从游艇出租站 11 到游艇出租站 nn 所需的最少租金。

输入输出样例

输入 #1

3
5 15
7

输出 #1

12

说明/提示

n≤200n≤200,保证计算过程中任何时刻数值都不超过 106106。

算法:最短路径——dijkstra算法

思路:

半矩阵输入,游艇出租站 i 到游艇出租站 j 之间的租金为 r(i,j),可以将个出租站之间看成一个有向图,用一个二维数组存储各个出租站以及各个站之间的租金,然后很明显就是一个找最短路的算法,我用的是dijkstra,直接对着模板敲即可

代码奉上:

#include<stdio.h>
#define size 10001
#define most 0x3f3f3f3f
int dist[size];//起点到其余各顶点的最短路径长度,初始化为无穷大
int before[size];//顶点到其所在的最短路径上的前一个顶点的数组下标信息,初始化为-1,可给出源点到此点的最短路径的具体路径
bool book[size];//用来标记顶点是否已经并入最短路径,初始化为false表示没有被纳入最短路径
int map[size][size];//用来存储各顶点之间的关系,map[x][y]中存储的值表示为x点到y点的距离
int n, m, s;//分别表示点的个数,有向边的个数,出发点(源点)的编号
void init() { //算法初始化
	book[s] = true; //标记源点,将源点纳入最短路径
	for (int i = 1; i <= n; i++) {
		if (i != s) {
			book[i] = false;//初始化用来标记的数组
		}
		before[i] = -1; //初始化前驱数组
		for (int li = 1; li <= n; li++) {//初始化存储图数据的数组
			if (i != li) {
				map[i][li] = most; //无穷值认为两个顶点之间不能到达
			} else {
				map[i][li] = 0; //一个顶点到自身顶点之间的距离为0
			}
		}
	}
}
void run_dijkstra() {
	for (int i = 1; i <= n - 1; i++) {
		int min = most, x;
		for (int j = 1; j <= n; j++) {//找到离源点最近且没有被纳入最短路径的顶点,设该点为x点
			if (!book[j] && dist[j] < min) {
				min = dist[j];
				x = j;
			}
		}
		book[x] = true;//将离更新点最近的点x点标记
		for (int j = 1; j <= n; j++) {//更新与x点相连的点的到源点距离
			if (!book[j] && (dist[x] + map[x][j] < dist[j])) {//此点没有被标记且通过x点做中转点可缩短此点到源点的距离
				dist[j] = dist[x] + map[x][j];//更新此点到源点的距离
				before[j] = x;//更新此点的前驱点为x点
			}
		}
	}
}
int main() {
	scanf("%d", &n);
	s = 1;
	init();//输入n,m,s之后再初始化
	for (int i = 1; i <= n - 1; i++) { //输入数据
		for (int k = i + 1; k <= n; k++) { //上游上艇,下游下艇,故用i+1
			scanf("%d", &map[i][k]);
		}
	}
	for (int i = 1; i <= n; i++) { //初始化dist数组,这里初始与源点想连的其余各个顶点的路程
		dist[i] = map[s][i];
	}
	run_dijkstra();
	printf("%d ", dist[n]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值