ダイクストラアルゴリズムの応用

1. 問題の説明

貧乏旅行?「貧しい」旅行ですか?
制限時間:  1000MS メモリ制限:  10000 KB

説明

かわいそうなA君には、T国へ貧しい旅行をするという夢がありますが、現実は残酷です。
リトル A が位置する世界には合計 n (n<=500) か国があり、国を結ぶ道路は合計 E (E<=50000) あります。i 番目の国は、入国する外国人に対して Bi を請求します
費用と、幼い A の家族は s 国に住んでいますが、国間の移動にはこれらの道路を使用し、最終的に t 国に到達する必要があります (s 国から t 国に直接行けるほど幸運でない限り) しかし、貧しい A 君は M (M<=100) 元しか持っていないので、旅費を慎重に計画しなければなりませんが、
同時に、A 君は本当に T 国に憧れているので、最短距離で T 国に行きたいと考えています。できるだけ早くお願いします。この質問に小さな
A は困惑しました。今度は、国 t に到達するまでの最短距離を計算するのを手伝ってほしいと頼みました。

入力

最初の行の入力 T (T<=10) は、T セットのデータがあることを意味します。各データセットの最初の行に n、E、s、t、M を入力します。それぞれ、
リトル A が位置する世界の国の数、国間の道路の総数、リトル A の国籍、国を示します。小さな A が憧れていること、そして小さな A の家族背景 ; 次の行に、
i 番目の国が徴収する通行料金を表す n 個の正の整数 Bi を入力します (A は s 国の出身なので、s 国は徴収しません) 、ただし国 t が請求されます); 次に、E の各行に 3 つを
入力します。正の整数 u(1<=u<=n)、v(1<=v<=n)、w、は、無向性があることを示します。国 u と国 v の間の長さ w のエッジ (複数のエッジがある場合があります) 入力により、最終結果が int をオーバーフローしないことが保証されます。

出力

正の整数を T 行出力します。i 番目の行は、データ A の i 番目のグループが M 元を超えずに t 国に到達する最短経路を表します。小さな A が国 t に到達できない場合は、
-1 を出力します。

サンプル入力

3 
2 2 1 2 10 
20 10 
1 2 1 
1 2 2 
3 1 1 3 10 
1 1 1 
2 3 1 
3 3 1 3 10 
1 11 1 1 2 1 1 
2 
3 2 
3 1

サンプル出力

1 
-1 
-1

2. アルゴリズム解析

この質問の目的は、S 国から T 国への最短経路を見つけることです。明らかに、ダイクストラのアルゴリズムを使用する必要があります。対応する料金はエッジ間の重みとみなすことができ、最終コストは最短経路の重みの合計となります。M より小さい場合、小さな A は到達できますが、M より大きい場合、小さな A は到達できません。

#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;

// 结构体表示图中的一条边
struct country {
	int v, w; // 顶点和权重
};

vector <country> world[505]; // 图的邻接表表示

// 结构体表示图中的一个顶点
struct vertex {
	int m, dis, v; // m: 剩余的金钱,dis: 距离,v: 顶点
};

// 自定义比较函数,用于优先队列的排序
struct mycompare {
	bool operator()(vertex a, vertex b) {
		return a.dis > b.dis; // 根据距离比较顶点
	}
};

priority_queue<vertex, vector<vertex>, mycompare> arr; // 用于Dijkstra算法的优先队列

int main() {
	int T, n, E, s, t, M, x, y, z;
	cin >> T; // 读取测试用例的数量

	int cost[505]; // 数组用于存储每个顶点的成本
	int distance[505][105]; // 二维数组用于存储最短距离
	bool flag[505][105]; // 二维数组用于跟踪访问过的顶点

	while (T--) { // 遍历每个测试用例
		memset(distance, -1, sizeof(distance)); // 将距离数组初始化为-1
		memset(flag, true, sizeof(flag)); // 将标记数组初始化为true

		cin >> n >> E >> s >> t >> M; // 读取顶点数、边数、起点、终点和初始金钱

		for (int i = 1; i <= n; i++)
			cin >> cost[i]; // 读取每个顶点的成本

		for (int i = 0; i < E; i++) {
			cin >> x >> y >> z; // 读取边的起点、终点和权重
			country temp;
			temp.v = y;
			temp.w = z;
			world[x].push_back(temp); // 将边添加到起点的邻接表中
			temp.v = x;
			world[y].push_back(temp); // 将边添加到终点的邻接表中(无向图)
		}

		vertex temp;
		temp.m = M; temp.dis = 0; temp.v = s; distance[temp.v][M] = 0;
		arr.push(temp); // 将起点加入优先队列

		while (!arr.empty()) {
			temp = arr.top(); // 取出距离最小的顶点
			arr.pop();

			int p = temp.v;
			if (!flag[p][temp.m] || temp.dis > distance[temp.v][temp.m]) continue; // 如果顶点已被访问过或距离更大,则跳过此次循环

			flag[p][temp.m] = false; // 标记顶点为已访问

			for (int i = 0; i < world[p].size(); i++) {
				int v = world[p][i].v;
				if (v == s) continue; // 如果顶点为起点,则跳过此次循环

				if (temp.m >= cost[v] && (distance[v][temp.m - cost[v]] == -1 || temp.dis + world[p][i].w < distance[v][temp.m - cost[v]])) {
					distance[v][temp.m - cost[v]] = temp.dis + world[p][i].w; // 更新距离数组

					vertex point;
					point.dis = temp.dis + world[p][i].w;
					point.m = temp.m - cost[v];
					point.v = v;
					arr.push(point); // 将新的顶点加入优先队列
				}
			}
		}

		int ans = 1000000;
		bool index = 0;

		for (int i = 0; i <= M; i++) {
			if (distance[t][i] != -1) {
				ans = min(ans, distance[t][i]); // 更新最短距离
				index = 1;
			}
		}

		if (!index)
			cout << -1 << endl;
		else
			cout << ans << endl;

		for (int i = 1; i <= n; i++)
			world[i].clear(); // 清空邻接表
	}
}

おすすめ

転載: blog.csdn.net/lyhizjj/article/details/130749526