7月16日-最短路训练1
P3385 【模板】负环
#include <iostream>
#include <queue>
#define int long long
#define toson(x) for (int p = head[x]; ~p; p = e[p].nxt)
using namespace std;
const int MaxN = 1e5 + 10, MaxM = 2e5 + 10;
struct Edge {
int to, w, nxt;
} e[MaxM << 1];
struct Node {
int x, w;
bool operator<(const Node &j) const {
return w > j.w;
}
};
int head[MaxN], dis[MaxN], cnt, n, m, s, t;
queue<Node> q;
int vis[MaxN], flag[MaxN];
int add(int u, int v, int w) {
return e[++cnt] = {v, w, head[u]}, head[u] = cnt;
}
int Record(Node u, Edge e) {
if (u.w + e.w >= dis[e.to]) return 0;
dis[e.to] = u.w + e.w;
if (flag[e.to]) return 0;
q.push({e.to, dis[e.to]}), flag[e.to] = 1;
if ((++vis[e.to]) > n) return -1;
return e.to;
}
bool Solve() {
cin >> n >> m;
fill(head + 1, head + n + 1, -1), fill(dis + 1, dis + n + 1, 1e18), fill(vis + 1, vis + n + 1, 0), fill(flag + 1, flag + n + 1, 0);
cnt = 0;
queue<Node>().swap(q);
for (int i = 1, u, v, w; i <= m; i++) {
cin >> u >> v >> w;
if (w >= 0) add(u, v, w), add(v, u, w);
else add(u, v, w);
}
for (Record({0, 0}, {1, 0, 0}); !q.empty(); ) {
Node tmp = q.front();
q.pop();
flag[tmp.x] = 0;
toson(tmp.x) {
if (Record(tmp, e[p]) == -1) return 1;
}
}
return 0;
}
signed main() {
for (cin >> t; t; t--) {
cout << (Solve() ? "YES" : "NO") << '\n';
}
return 0;
}
到
#include <iostream>
#include <queue>
#define int long long
#define toson(x) for (int p = head[x]; ~p; p = e[p].nxt)
using namespace std;
const int MaxN = 1e5 + 10, MaxM = 2e5 + 10;
struct Edge {
int to, w, nxt;
} e[MaxM << 1];
struct Node {
int x, w;
bool operator<(const Node &j) const {
return w > j.w;
}
};
int head[MaxN], dis[MaxN], cnt, n, m, s, t;
queue<Node> q;
int vis[MaxN], flag[MaxN];
int add(int u, int v, int w) {
return e[++cnt] = {v, w, head[u]}, head[u] = cnt;
}
int Record(Node u, Edge e) {
if (dis[u.x] + e.w >= dis[e.to]) return 0;
dis[e.to] = dis[u.x] + e.w;
if (flag[e.to]) return 0;
q.push({e.to, dis[e.to]}), flag[e.to] = 1;
if ((++vis[e.to]) > n) return -1;
return e.to;
}
bool Solve() {
cin >> n >> m;
fill(head + 1, head + n + 1, -1), fill(dis + 1, dis + n + 1, 1e18), fill(vis + 1, vis + n + 1, 0), fill(flag + 1, flag + n + 1, 0);
cnt = 0;
queue<Node>().swap(q);
for (int i = 1, u, v, w; i <= m; i++) {
cin >> u >> v >> w;
if (w >= 0) add(u, v, w), add(v, u, w);
else add(u, v, w);
}
for (Record({0, 0}, {1, 0, 0}); !q.empty(); ) {
Node tmp = q.front();
q.pop();
flag[tmp.x] = 0;
toson(tmp.x) {
if (Record(tmp, e[p]) == -1) return 1;
}
}
return 0;
}
signed main() {
for (cin >> t; t; t--) {
cout << (Solve() ? "YES" : "NO") << '\n';
}
return 0;
}
由于SPFA用的不是单调队列,所以我们不可以用队列中存储的w作为该节点的dis
P1613 跑路
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int MaxN = 51, MaxK = 31;
int f[MaxK][MaxN][MaxN], n, m;
bool g[MaxK][MaxN][MaxN];
signed main() {
cin >> n >> m;
for (int p = 0; p < MaxK; p++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
f[p][i][j] = 1e18;
}
}
}
for (int i = 1, u, v; i <= m; i++) {
cin >> u >> v, g[0][u][v] = 1, f[0][u][v] = 1;
}
for (int p = 1; p < MaxK; p++) {
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
g[p][i][j] |= g[p - 1][i][k] | g[p - 1][k][j];
}
}
}
}
for (int i = 1; i <= n; i++) {
f[0][i][i] = 0;
}
for (int p = 1; p < MaxK; p++) {
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
f[p][i][j] = min(f[p][i][j], f[p - 1][i][j]);
if (g[p][k][j]) {
f[p][i][j] = min(f[p][i][j], f[p - 1][i][k] + 1);
}
}
}
}
}
cout << f[MaxK - 1][1][n] << '\n';
return 0;
}
到
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int MaxN = 51, MaxK = 64;
int f[MaxK][MaxN][MaxN], n, m;
bool g[MaxK][MaxN][MaxN];
signed main() {
cin >> n >> m;
for (int p = 0; p < MaxK; p++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
f[p][i][j] = 1e18;
}
}
}
for (int i = 1, u, v; i <= m; i++) {
cin >> u >> v, g[0][u][v] = 1, f[0][u][v] = 1;
}
for (int p = 1; p < MaxK; p++) {
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
g[p][i][j] |= g[p - 1][i][k] & g[p - 1][k][j];
}
}
}
}
for (int i = 1; i <= n; i++) {
f[0][i][i] = 0;
}
for (int p = 1; p < MaxK; p++) {
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
f[p][i][j] = min(f[p][i][j], f[p - 1][i][j]);
if (g[p][k][j]) {
f[p][i][j] = min(f[p][i][j], f[p - 1][i][k] + 1);
}
}
}
}
}
cout << f[MaxK - 1][1][n] << '\n';
return 0;
}
从
g[p][i][j] |= g[p - 1][i][k] | g[p - 1][k][j];
g[p][i][j] |= g[p - 1][i][k] & g[p - 1][k][j];
???我也是无语了,两条路径是否可行推导到合并路径是否可行,当然应该取交集
P5304 [GXOI/GZOI2019] 旅行者
#include <iostream>
#include <queue>
#define int long long
#define toson(x) for (int p = head[x]; ~p; p = e[p].nxt)
using namespace std;
const int MaxN = 1e5 + 10, MaxM = 5e5 + 10;
struct Edge {
int to, w, nxt;
} e[MaxM << 1];
struct Node {
int x, w;
bool operator<(const Node &j) const {
return w > j.w;
}
};
int head[MaxN], dis[MaxN], cnt, n, m, s, k, t;
priority_queue<Node> q;
bool vis[MaxN], isk[MaxN];
int add(int u, int v, int w) {
return e[++cnt] = {v, w, head[u]}, head[u] = cnt;
}
int Record(Node u, Edge e) {
if (u.w + e.w >= dis[e.to]) return 0;
dis[e.to] = u.w + e.w, q.push({e.to, dis[e.to]});
return e.to;
}
void Dij(int k) {
priority_queue<Node>().swap(q);
fill(dis, dis + n + 1, 1e18), fill(vis, vis + n + 1, 0);
for (int i = 1; i <= n; i++) {
if (isk[i] && i & (1 << k)) {
Record({0, 0}, {i, 0, 0});
}
}
for (; !q.empty();) {
Node tmp = q.top();
q.pop();
if (vis[tmp.x]) continue;
vis[tmp.x] = 1;
toson(tmp.x) Record(tmp, e[p]);
}
}
void Solve() {
cin >> n >> m >> k;
fill(head, head + n + 1, -1), fill(isk, isk + n + 1, 0), cnt = 0;
for (int i = 1, u, v, w; i <= m; i++) {
cin >> u >> v >> w;
add(u, v, w), add(v, u, w);
}
for (int i = 1, x; i <= k; i++) {
cin >> x, isk[x] = 1;
}
int ans = 1e18;
for (int i = 0; i < 19; i++) {
Dij(i);
for (int j = 1; j <= n; j++) {
if (isk[j] && !(j & (1 << i))) {
ans = min(ans, dis[j]);
}
}
}
cout << ans << '\n';
}
signed main() {
for (cin >> t; t; t--) {
Solve();
}
return 0;
}
#include <iostream>
#include <queue>
#define int long long
#define toson(x) for (int p = head[x]; ~p; p = e[p].nxt)
using namespace std;
const int MaxN = 1e5 + 10, MaxM = 5e5 + 10;
struct Edge {
int to, w, nxt;
} e[MaxM << 1];
struct Node {
int x, w;
bool operator<(const Node &j) const {
return w > j.w;
}
};
int head[MaxN], dis[MaxN], cnt, n, m, s, k, t, ans;
priority_queue<Node> q;
bool vis[MaxN], isk[MaxN];
int add(int u, int v, int w) {
return e[++cnt] = {v, w, head[u]}, head[u] = cnt;
}
int Record(Node u, Edge e) {
if (u.w + e.w >= dis[e.to]) return 0;
dis[e.to] = u.w + e.w, q.push({e.to, dis[e.to]});
return e.to;
}
void Dij(int k, bool flag) {
priority_queue<Node>().swap(q);
fill(dis, dis + n + 1, 1e18), fill(vis, vis + n + 1, 0);
for (int i = 1; i <= n; i++) {
if (isk[i] && (bool)(i & (1 << k)) == flag) {
Record({0, 0}, {i, 0, 0});
}
}
for (; !q.empty();) {
Node tmp = q.top();
q.pop();
if (vis[tmp.x]) continue;
vis[tmp.x] = 1;
toson(tmp.x) Record(tmp, e[p]);
}
for (int j = 1; j <= n; j++) {
if (isk[j] && (bool)(j & (1 << k)) != flag) {
ans = min(ans, dis[j]);
}
}
}
void Solve() {
cin >> n >> m >> k;
fill(head, head + n + 1, -1), fill(isk, isk + n + 1, 0), cnt = 0;
for (int i = 1, u, v, w; i <= m; i++) {
cin >> u >> v >> w;
add(u, v, w);
}
for (int i = 1, x; i <= k; i++) {
cin >> x, isk[x] = 1;
}
ans = 1e18;
for (int i = 0; i < 19; i++) {
Dij(i, 1), Dij(i, 0);
}
cout << ans << '\n';
}
signed main() {
for (cin >> t; t; t--) {
Solve();
}
return 0;
}
注意!!!是单向边!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

浙公网安备 33010602011771号