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;
}

注意!!!是单向边!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

posted @ 2026-07-16 21:13  yabnto  阅读(9)  评论(0)    收藏  举报