目录
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();
}