UVA 1599 Ideal Path
评测传送门1
评测传送门2
题目大意:@Sparky_14145提供的翻译很清楚,不再赘述。
解题思路:
源点:
1
1
1 ,汇点:
n
n
n
先逆向求一遍单汇最短路,然后再从源点正向
B
F
S
BFS
BFS求最小字典序的路径。
在正向
B
F
S
BFS
BFS 的时候,要将当前最小的可能是最优路径上的点全部加进队列进行扩展,即满足
d
i
s
t
[
j
]
+
w
[
i
]
=
d
i
s
t
[
u
]
dist[j] + w[i] = dist[u]
dist[j]+w[i]=dist[u]的那些结点
j
j
j。在此题中所有的边权都是
1
1
1,所以
w
[
i
]
=
1
w[i]=1
w[i]=1.
AcCoding:
#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 100010, M = 400010;
int h[N], e[M], ne[M], w[M], idx;
int dist[N],res[M];
bool vis[N];
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void rebfs(int root) {
memset(dist, 0x3f, sizeof dist);
memset(vis, false, sizeof vis);
dist[root] = 0;
queue<int> q;
q.push(root);
while (q.size()) {
int u = q.front(); q.pop();
vis[u] = true;
for (int i = h[u];i != -1;i = ne[i]) {
int j = e[i];
if (dist[j] > dist[u] + 1) {
dist[j] = dist[u] + 1;
q.push(j);
}
}
}
}
void bfs(int root,int end) {
memset(vis, false, sizeof vis);
memset(res, 0x3f, sizeof res);
queue<int> q;
q.push(root);
vis[root] = true;
while (q.size()) {
int u = q.front();q.pop();
if (u == end) break;
int min1 = 0x3f3f3f3f;
for (int i = h[u];i != -1;i = ne[i]) {
int j = e[i];
if (dist[u] == dist[j] + 1 && w[i] < min1) min1 = w[i];
}
if (min1 != 0x3f3f3f3f) {
for (int i = h[u];i != -1;i = ne[i]) {
int j = e[i];
if (!vis[j] && dist[u] == dist[j] + 1 && w[i] == min1) {
q.push(j);
vis[j] = true;
}
}
}
int idx = dist[1] - dist[u];
res[idx] = min(res[idx], min1);
}
}
int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
idx = 0;
memset(h, -1, sizeof h);
for (int i = 1;i <= m;i++) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
if (a == b) continue;
add(a, b, c), add(b, a, c);
}
int start = 1, end = n;
rebfs(end);
printf("%d\n", dist[start]);
bfs(start,end);
for (int i = 0;i < dist[start];i++) {
printf("%d", res[i]);
if (i < dist[start] - 1) printf(" ");
}
puts("");
}
return 0;
}
UPC 4431 香港记者
评测传送门
题目大意:
与上面那个题类似,这个题是在最短路的基础之上同时要满足路径上结点的点权构成序列的字典序最小。
解题思路:
这个题强调是有向图,因此需要建两次图,一次正向图,一次反向图。反向图的作用也是求单汇最短路。在正向图上跑
B
F
S
BFS
BFS 寻找最优路径,扩展的时候,找到当前遍历到的可能的最小点权的的结点。与上一个题的操作操作类似,代码我也是直接拿上一个代码稍微更改了一点。特别的,起点和终点的点权一定在路径中。
ACoding:
#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 200010, M = 800010;
int h[N], e[M], ne[M], w[M], idx;
ll dist[N];
int val[N];
bool vis[N];
vector<int> res;
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void rebfs(int root) {
memset(dist, -1, sizeof dist);
dist[root] = 0;
queue<int> q;
q.push(root);
while (q.size()) {
int u = q.front(); q.pop();
vis[u] = true;
for (int i = h[u];i != -1;i = ne[i]) {
int j = e[i];
if (dist[j] == -1 || dist[j] > dist[u] + w[i]) {
dist[j] = dist[u] + w[i];
q.push(j);
}
}
}
}
void bfs(int root,int end) {
memset(vis, false, sizeof vis);
queue<int> q;
q.push(root);
vis[root] = true;
while (q.size()) {
int u = q.front();q.pop();
if (u == end) break;
int min1 = 0x3f3f3f3f;
for (int i = h[u];i != -1;i = ne[i]) {
int j = e[i];
if (dist[u] == dist[j] + w[i] && val[j] < min1) min1 = val[j];
}
if (min1 != 0x3f3f3f3f) {
for (int i = h[u];i != -1;i = ne[i]) {
int j = e[i];
if (!vis[j] && dist[u] == dist[j] + w[i] && val[j] == min1) {
q.push(j);
vis[j] = true;
}
}
res.push_back(min1);
}
}
}
struct node {
int a, b, c;
}edge[M];
int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1;i <= n;i++) scanf("%d", &val[i]);
memset(h, -1, sizeof h);
for (int i = 1;i <= m;i++) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
add(b, a, c);
edge[i] = { a,b,c };
}
int start = 1, end = n;
rebfs(end);
printf("%lld\n", dist[start]);
memset(h, -1, sizeof h);
idx = 0;
for (int i = 1;i <= m;i++) add(edge[i].a, edge[i].b, edge[i].c);
bfs(start,end);
cout << val[1] << " ";
for (int i = 0;i < res.size();i++) {
printf("%d", res[i]);
if (i < res.size() - 1) printf(" ");
}
return 0;
}