Contest100000621 - 《算法笔记》10.4小节——图算法专题->最短路径

题目链接

A 算法7-15:迪杰斯特拉最短路径算法

  1. Dijkstra 算法,很简单啦。参考代码如下。
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 60;
const int INF = 0x3fffffff;

int G[MAXN][MAXN];
int n, s;
int d[MAXN];
bool vis[MAXN] = { false };

void dijkstra(){
	fill(d, d + MAXN, INF);
	d[s] = 0;
	for (int i = 0; i < n; i++) {
		int u = -1, MIN = INF;
		for(int j=0;j<n;j++)
			if (!vis[j] && d[j] < MIN) {
				u = j;
				MIN = d[j];
			}
		if (u == -1) return;
		vis[u] = true;
		for (int v = 0; v < n; v++)
			if (!vis[v] && G[u][v] && d[u] + G[u][v] < d[v])
				d[v] = d[u] + G[u][v];
	}
}

int main() {
	cin >> n >> s;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			cin >> G[i][j];
	dijkstra();
	bool first = true;
	for(int i=0;i<n;i++)
		if (i != s) {
			if (!first) cout << ' ';
			if (d[i] != INF)
				cout << d[i];
			else cout << -1;
			first = false;
		}
	return 0;
}

B 算法7-16:弗洛伊德最短路径算法

  1. 需要先处理一下邻接矩阵,将值为 0 的权值设置为 INF(不可达),最后输出的时候要将值为 INF 的权值输出为 -1。参考代码如下。
#include<iostream>
using namespace std;
const int MAXN = 60;
const int INF = 0x3fffffff;

int G[MAXN][MAXN], n;

void floyd() {
	for (int k = 0; k < n; k++)
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				if (G[i][k] != INF && G[k][j] != INF && G[i][k] + G[k][j] < G[i][j])
					G[i][j] = G[i][k] + G[k][j];
}
int main() {
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) {
			cin >> G[i][j];
			if (i != j && G[i][j] == 0)
				G[i][j] = INF;
		}
	floyd();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++)
			if (G[i][j] == INF)
				cout << -1 << ' ';
			else cout << G[i][j] << ' ';
		cout << endl;
	}
	return 0;
}

C 最短路径(未通过)

  1. 这道题结合了最短路径算法和大整数,结点的权值为2^{k},k 最大为500,因此如何表示权值是一个问题。不能把权值在输入的时候就模10万,那样在算最短路径的时候的权值已经不对了,最后算出来的最短路径肯定也就不对了。
  2. 这里想到的办法是用二进制串表示权值,模拟大整数运算。两个权值相加则为二进制串的相加,权值比较大小则为二进制串比较大小,具体思路见代码,可能写得比较复杂。
  3. 最后 d 数组存储的二进制串即为最短路径,直接把二进制串转换为十进制数再模10万就是最后的最短路径了。
  4. 很奇怪,不管怎么调试就是过不了。
//未通过
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
const int MAXN = 110;
const string INF = "2";
const int MOD = 100000;

int n, m;
struct node { int v; string dis; node(int v, string d) :v(v), dis(d) {} };
vector <node> adj[MAXN];
bool vis[MAXN] = { false };
string d[MAXN];

string add(string a, string b) {
	if (a.size() < b.size()) swap(a, b);
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	for (int i = 0; i < b.size(); i++) {
		a[i] += b[i] - '0';
		if (a[i] > '1') {
			a[i] -= 2;
			if (i == a.size() - 1) a += "0";
			a[i + 1]++;
		}
	}
	reverse(a.begin(), a.end());
	return a;
}
bool cmp_less(string a, string b) {
	if (a == INF) return false;
	else if (b == INF) return true;
	else if (a.size() == b.size()) return a < b;
	else if (a.size() < b.size()) return true;
	else return false;
}
int pow(string s) {
	reverse(s.begin(), s.end());
	int t = 1, ans = 0;
	for (int i = 0; i < s.size(); i++) {
		if (s[i] == '1')
			ans += t;
		t = 2 * t % MOD;
	}
	return ans % MOD;
}

void dijkstra() {
	fill(d, d + MAXN, INF);
	d[0] = "0";
	for (int i = 0; i < n; i++) {
		int u = -1;
		string MIN = INF;
		for (int j = 0; j < n; j++)
			if (!vis[j] && cmp_less(d[j], MIN)) {
				u = j;
				MIN = d[j];
			}
		if (u == -1) return;
		vis[u] = true;
		for (int j = 0; j < adj[u].size(); j++) {
			int v = adj[u][j].v;
			string dis = adj[u][j].dis;
			if (!vis[v] && cmp_less(add(d[u], dis), d[v]))
				d[v] = add(d[u], dis);
		}
	}
}

int main() {
	cin >> n >> m;
	int u, v;
	string dis = "1";
	while (m--) {
		cin >> u >> v;
		adj[u].push_back(node(v, dis));
		adj[v].push_back(node(u, dis));
		dis += "0";
	}
	dijkstra();
	for (int i = 1; i < n; i++)
		if (d[i] != INF)
			cout << pow(d[i]) << endl;
		else cout << -1 << endl;
	return 0;
}

D 最短路径

  1. 简单题。但是不知道为什么邻接矩阵过不了,邻接表就能过(o((⊙﹏⊙))o)。参考代码如下。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 1010;
const int INF = 0x3fffffff;

struct node {
	int v, dis;
	node(int v, int d) :v(v), dis(d) {}
};
int n, m, s, t;
vector <node> adj[MAXN];
int d[MAXN], pre[MAXN];
bool vis[MAXN] = { false };

void dijkstra() {
	fill(d, d + MAXN, INF);
	fill(vis, vis + MAXN, false);
	for (int i = 1; i <= n; i++) pre[i] = i;
	d[s] = 0;
	for (int i = 0; i < n; i++) {
		int u = -1, MIN = INF;
		for (int j = 1; j <= n; j++)
			if (!vis[j] && d[j] < MIN) {
				u = j;
				MIN = d[j];
			}
		if (u == -1) return;
		vis[u] = true;
		for (int j= 0; j < adj[u].size(); j++) {
			int v = adj[u][j].v;
			int dis = adj[u][j].dis;
			if (!vis[v]) {
				if (d[u] + dis < d[v]) {
					d[v] = d[u] + dis;
					pre[v] = u;
				}
				else if (d[u] + dis == d[v] && pre[v] > u)
					pre[v] = u;
			}
		}
	}
}
void dfs(int v) {
	if (v == s) {
		cout << v << ' ';
		return;
	}
	else {
		dfs(pre[v]);
		cout << v << ' ';
	}
}

int main() {
	while (cin >> n >> m >> s >> t) {
		for (int i = 1; i <= n; i++)
			adj[i].clear();
		for (int i = 0; i < m; i++) {
			int c1, c2, d;
			cin >> c1 >> c2 >> d;
			adj[c1].push_back(node(c2, d));
			adj[c2].push_back(node(c1, d));
		}
		dijkstra();
		if (d[t] == INF)
			cout << "can't arrive" << endl;
		else {
			cout << d[t] << endl;
			dfs(t);
			cout << endl;
		}
	}
	return 0;
}

E 最短路径问题

  1. 直接套用 Dijkstra + DFS 模板即可。参考代码如下。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 1010;
const int INF = 0x3fffffff;

struct node {
	int v, dis;
	node(int v, int d) :v(v), dis(d) {}
};
vector <node> adj[MAXN];
int cost[MAXN][MAXN], d[MAXN];
vector <int> pre[MAXN];
vector <int> temp_path;
int min_cost;
bool vis[MAXN];
int n, m, s, t;

void dijkstra() {
	fill(d, d + MAXN, INF);
	fill(vis, vis + MAXN, false);
	d[s] = 0;
	for (int i = 0; i < n; i++) {
		int u = -1, MIN = INF;
		for (int j = 1; j <= n; j++)
			if (!vis[j] && d[j] < MIN) {
				u = j;
				MIN = d[j];
			}
		if (u == -1) return;
		vis[u] = true;
		for (int j = 0; j < adj[u].size(); j++) {
			int v = adj[u][j].v;
			int dis = adj[u][j].dis;
			if (!vis[v]) {
				if (d[u] + dis < d[v]) {
					d[v] = d[u] + dis;
					pre[v].clear();
					pre[v].push_back(u);
				}
				else if (d[u] + dis == d[v])
					pre[v].push_back(u);
			}
		}
	}
}
void dfs(int v) {
	if (v == s) {
		temp_path.push_back(v);
		int temp_cost = 0;
		for (int i = temp_path.size() - 1; i > 0; i--)
			temp_cost += cost[temp_path[i]][temp_path[i - 1]];
		if (temp_cost < min_cost)
			min_cost = temp_cost;
		temp_path.pop_back();
	}
	temp_path.push_back(v);
	for (int i = 0; i < pre[v].size(); i++)
		dfs(pre[v][i]);
	temp_path.pop_back();
}

int main() {
	while (cin >> n >> m && n + m) {
		for (int i = 1; i <= n; i++)
			adj[i].clear();
		for (int i = 1; i <= n; i++)
			pre[i].clear();
		fill(cost[0], cost[0] + MAXN * MAXN, INF);
		min_cost = INF;
		for (int i = 1; i <= m; i++) {
			int a, b, d, p;
			cin >> a >> b >> d >> p;
			cost[a][b] = cost[b][a] = p;
			adj[a].push_back(node(b, d));
			adj[b].push_back(node(a, d));
		}
		cin >> s >> t;
		dijkstra();
		dfs(t);
		cout << d[t] << ' ' << min_cost << endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42717165/article/details/87876004