最短路— dijkstra 松弛操作变形

 

目录

 1.营救 - 洛谷

2.P1576 最小花费 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 最长路

3.P3905 道路重建 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 图的处理


 1.营救 - 洛谷

之前用二分并查集和最小生成树写过,现在学习了dijkstra的解法。

。只需要将原算法的松弛操作修改为求最大边的最小值即可。此时dis[i]数组表示起点s到i的最大边的最小值

#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define int ll
#define mm(a) memset(a,0,sizeof(a))
#pragma warning (disable :4996);
const int N = 1e6 + 10;
const int mod = (1e9) + 7;
int T, n, m, k, q;
int a, b, c;
int s, e;
struct edge {
	int  to, pw;
	int operator<(const edge& a)const {
		return pw > a.pw;
	}
};
vector<edge>gra[N];
int dis[N];
int vis[N];
int nx[N];
void dij() {
	
	for (int j = 1; j <= n; j++)dis[j] = INT_MAX;
	dis[s] = 0;
	int now = s;
	priority_queue<edge>q;
	q.push({ now,dis[now] });
	while (!q.empty()) {
		now = q.top().to;
		
		q.pop();
		if (vis[now])continue;
		vis[now] = 1;
		for (auto x : gra[now]) {
			int to = x.to;
			int k = max(dis[now], x.pw);//到now的最大边与到to的边比较谁是最大边
			if (vis[to] == 0 && k<dis[to]) {//更新最小值
				dis[to] =  k;	
				q.push({ to,dis[to] });
			}
		}
	}
	cout << dis[e] << endl;
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
	//freopen("out.txt", "w", stdout);
#endif
	
	cin >> n >> m >> s >> e;
	for (int j = 1; j <= m; j++) {
		cin >> a >> b >> c;
		gra[a].push_back({ b,c });
		gra[b].push_back({ a,c });
	}
	dij();
}

2.P1576 最小花费 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 最长路

给的权值是扣除的百分比,也就是说经过该边,路径长将为原来的(1-z%),要使最少的总费用也就是找出最大的(1-z%)的总乘积

所以松弛操作改为更新节点的最大(1-z%)同时,dis[i]表示起,到i最大汇率,也就变成了最长路问题。说是最长路不太贴切。就是找出(1-z%)乘积最大的那条路

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define int ll
#pragma warning(disable:4996);
#define mm(a) memset(a,0,sizeof(a))
#define memset(a,b) memset(a,b,sizeof(a))
const int N = 2e5 + 10;
int T, n, m, k, q;
int a, b, c; int t1, t2;
struct edge {
	int to;
	double pw;
	int operator<(const edge& a)const {
		return pw < a.pw;//求最长路
	}
};
vector<edge>gra[N];
int vis[N];
double dis[N];//此时dis表示起点到下标的最大汇率
void dij() {
	
	int now = t1;
	dis[now] = 1.0;//起始点没有转移,没有扣款,所以为1
	priority_queue<edge>q;
	q.push({ now,dis[now] });
	while (!q.empty()) {
		now = q.top().to;
		q.pop();
		if(vis[now])continue;
			vis[now]=1;
			for (auto x : gra[now]) {
				int to = x.to;
				if (!vis[to] && dis[to] < dis[now] * (1.0-(0.01 * x.pw))) {
                    //更新最长的1-z%
					dis[to] = (double)dis[now] * (1.0-(0.01 * x.pw));
					q.push({ to,dis[to] });

				}
			}
	}
	printf("%.8lf", (double)100/dis[t2]);
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0);
#ifndef ONLINE_JUDGE
	//freopen("out.txt", "w", stdout);
#endif
	cin >> n >> m;
	for (int j = 1; j <= m; j++) {
		double cc;
		cin >> a >> b >> cc;
	
		gra[a].push_back({ b,cc });
		gra[b].push_back({ a,cc });
	}
	cin >> t1 >> t2;
	dij();
}

3.P3905 道路重建 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 图的处理

 把完好的边看作修复费用为0的路径,被摧毁的边看作带权路径。就非常简单了。找出这个重构图的最短路即可。处理完直接最短路模板就能解决

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define int ll
#pragma warning(disable:4996);
#define mm(a) memset(a,0,sizeof(a))
#define memset(a,b) memset(a,b,sizeof(a))
const int N = 2e3 + 10;
int T, n, m, k, q;
int a, b, c; int t1, t2;
struct edge {
	int to;
	int pw;
	int operator<(const edge& a)const {
		return pw > a.pw;
	}
};
vector<edge>gra[N];
int vis[N];
int dis[N];
int des[N][N];
int nx[N];
int mp[N][N];
int sum = 0;
int dij() {
	memset(dis, 0x3f);
	int now = a;
	dis[now] = 0;
	priority_queue<edge>q;
	q.push({ now,dis[now] });

	while (!q.empty()) {
		now = q.top().to;
		q.pop();
		if (vis[now])continue;
		vis[now] = 1;
		for (auto x : gra[now]) {
			int to = x.to;
			if (des[now][to] == 0)x.pw = 0;
			if (!vis[to] && dis[to] > dis[now] + x.pw) {
				dis[to] = dis[now] + x.pw;
				q.push({ to,dis[to] });
				nx[now] = to;
			}
		}
	}
	cout << dis[b];
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0);
#ifndef ONLINE_JUDGE
	//freopen("out.txt", "w", stdout);
#endif
	cin >> n >> m;
	for (int j = 1; j <= m; j++) {
		cin >> a >> b >> c;
		gra[a].push_back({ b,c });
		gra[b].push_back({ a,c });
	}
	cin >> k;
	while (k--) {
		cin >> a >> b;
		des[a][b] = 1;
		des[b][a] = 1;
	}
	
	cin >> a >> b;
	dij();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值