Initial commit: C++ courseware
This commit is contained in:
commit
4a4ee7c287
1789 files changed
+373489
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,50 @@
|
||||
// P3371:非负边权的单源最短路,邻接表朴素实现。
|
||||
// C++11;时间 O(n*n+m),空间 O(n+m)。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
|
||||
struct Edge {
|
||||
int to;
|
||||
ll w;
|
||||
};
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m, s;
|
||||
if (!(cin >> n >> m >> s)) return 0;
|
||||
vector<vector<Edge>> g(n + 1);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v;
|
||||
ll w;
|
||||
cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
}
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
vector<bool> used(n + 1, false);
|
||||
dis[s] = 0; // 源点可一步不走;其他点尚未找到路线。
|
||||
for (int round = 0; round < n; ++round) {
|
||||
int u = -1;
|
||||
for (int v = 1; v <= n; ++v) {
|
||||
if (!used[v] && (u == -1 || dis[v] < dis[u])) {
|
||||
u = v;
|
||||
}
|
||||
}
|
||||
// 最小候选都不可达时,其余未确定点也不可达。
|
||||
if (u == -1 || dis[u] == INF) break;
|
||||
used[u] = true;
|
||||
for (const Edge& e : g[u]) {
|
||||
ll nd = dis[u] + e.w;
|
||||
if (nd < dis[e.to]) dis[e.to] = nd;
|
||||
}
|
||||
}
|
||||
for (int v = 1; v <= n; ++v) {
|
||||
if (v > 1) cout << ' ';
|
||||
cout << (dis[v] == INF ? 2147483647LL : dis[v]);
|
||||
}
|
||||
cout << '\n';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// P3371:相同的朴素 Dijkstra,使用链式前向星保存图。
|
||||
// 顶点编号为 1..n;边编号 0 表示边链结束。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m, s;
|
||||
if (!(cin >> n >> m >> s)) return 0;
|
||||
vector<int> head(n + 1, 0), to(m + 5), nxt(m + 5);
|
||||
vector<ll> weight(m + 5);
|
||||
int cnt = 0;
|
||||
auto add = [&](int u, int v, ll w) {
|
||||
++cnt;
|
||||
to[cnt] = v;
|
||||
weight[cnt] = w;
|
||||
nxt[cnt] = head[u]; // 新边先接上旧表头,再更新表头。
|
||||
head[u] = cnt;
|
||||
};
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v;
|
||||
ll w;
|
||||
cin >> u >> v >> w;
|
||||
add(u, v, w);
|
||||
}
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
vector<bool> used(n + 1, false);
|
||||
dis[s] = 0;
|
||||
for (int round = 0; round < n; ++round) {
|
||||
int u = -1;
|
||||
for (int v = 1; v <= n; ++v) {
|
||||
if (!used[v] && (u == -1 || dis[v] < dis[u])) u = v;
|
||||
}
|
||||
if (u == -1 || dis[u] == INF) break;
|
||||
used[u] = true;
|
||||
for (int i = head[u]; i; i = nxt[i]) {
|
||||
int v = to[i];
|
||||
ll nd = dis[u] + weight[i];
|
||||
if (nd < dis[v]) dis[v] = nd;
|
||||
}
|
||||
}
|
||||
for (int v = 1; v <= n; ++v) {
|
||||
if (v > 1) cout << ' ';
|
||||
cout << (dis[v] == INF ? 2147483647LL : dis[v]);
|
||||
}
|
||||
cout << '\n';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// 教学扩展:非负权有向图中,求 s 到 t 的距离并恢复一条最短路线。
|
||||
// 输入第一行 n m s t,接着 m 行 u v w。与 P3371 的输入不同。
|
||||
// 可达:第一行输出距离,第二行输出路线中的顶点编号。
|
||||
// 不可达:只输出 UNREACHABLE。C++11;时间 O(n*n+m)。
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
|
||||
struct Edge {
|
||||
int to;
|
||||
ll w;
|
||||
};
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m, s, t;
|
||||
if (!(cin >> n >> m >> s >> t)) return 0;
|
||||
vector<vector<Edge>> g(n + 1);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v;
|
||||
ll w;
|
||||
cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
}
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
vector<bool> used(n + 1, false);
|
||||
vector<int> pre(n + 1, -1);
|
||||
dis[s] = 0;
|
||||
for (int round = 0; round < n; ++round) {
|
||||
int u = -1;
|
||||
for (int v = 1; v <= n; ++v) {
|
||||
if (!used[v] && (u == -1 || dis[v] < dis[u])) u = v;
|
||||
}
|
||||
if (u == -1 || dis[u] == INF) break;
|
||||
used[u] = true;
|
||||
for (const Edge& e : g[u]) {
|
||||
ll nd = dis[u] + e.w;
|
||||
if (nd < dis[e.to]) {
|
||||
dis[e.to] = nd;
|
||||
pre[e.to] = u; // 与成功改善距离的路线保持一致。
|
||||
}
|
||||
}
|
||||
}
|
||||
// 没有路线时不能只把终点放进列表,伪装成一条路径。
|
||||
if (dis[t] == INF) {
|
||||
cout << "UNREACHABLE\n";
|
||||
return 0;
|
||||
}
|
||||
vector<int> path;
|
||||
for (int v = t; v != -1; v = pre[v]) path.push_back(v);
|
||||
reverse(path.begin(), path.end());
|
||||
cout << dis[t] << '\n';
|
||||
for (size_t i = 0; i < path.size(); ++i) {
|
||||
if (i) cout << ' ';
|
||||
cout << path[i];
|
||||
}
|
||||
cout << '\n';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// 教材例 10-1 / 洛谷 P3371:非负边权单源最短路。
|
||||
// 输入 n m s,随后 m 行 u v w;有向边,可含重边和零权边。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
using State = pair<ll, int>;
|
||||
struct Edge { int to; ll w; };
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m, s;
|
||||
if (!(cin >> n >> m >> s)) return 0;
|
||||
vector<vector<Edge>> g(n + 1);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v; ll w;
|
||||
cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
}
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
priority_queue<State, vector<State>, greater<State>> q;
|
||||
dis[s] = 0;
|
||||
q.push({0, s});
|
||||
while (!q.empty()) {
|
||||
State cur = q.top();
|
||||
q.pop();
|
||||
ll d = cur.first;
|
||||
int u = cur.second;
|
||||
if (d != dis[u]) continue; // 旧记录不再扫描出边
|
||||
for (const auto &e : g[u]) {
|
||||
int v = e.to;
|
||||
ll nd = d + e.w;
|
||||
if (nd < dis[v]) {
|
||||
dis[v] = nd;
|
||||
q.push({nd, v});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= n; ++i)
|
||||
cout << (dis[i] == INF ? 2147483647LL : dis[i])
|
||||
<< (i == n ? '\n' : ' ');
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// 备份版 Bellman–Ford;输入必须没有源点可达的负环。
|
||||
// 输入输出同 P3371;可以用自拟负权无环图验证,未包含判环功能。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
struct Edge { int u, v; ll w; };
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m, s;
|
||||
if (!(cin >> n >> m >> s)) return 0;
|
||||
vector<Edge> edges(m);
|
||||
for (auto &e : edges) cin >> e.u >> e.v >> e.w;
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
dis[s] = 0;
|
||||
for (int k = 1; k < n; ++k) {
|
||||
vector<ll> old = dis;
|
||||
bool changed = false;
|
||||
for (const auto &e : edges) {
|
||||
if (old[e.u] == INF) continue;
|
||||
ll nd = old[e.u] + e.w;
|
||||
if (nd < dis[e.v]) {
|
||||
dis[e.v] = nd;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (!changed) break;
|
||||
}
|
||||
for (int i = 1; i <= n; ++i)
|
||||
cout << (dis[i] == INF ? 2147483647LL : dis[i])
|
||||
<< (i == n ? '\n' : ' ');
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// FIFO SPFA;输入必须没有源点可达的负环,最坏时间 O(nm)。
|
||||
// 输入输出同 P3371;一般负权图应使用第 4 份中的判环版本。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
struct Edge { int to; ll w; };
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m, s;
|
||||
if (!(cin >> n >> m >> s)) return 0;
|
||||
vector<vector<Edge>> g(n + 1);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v; ll w;
|
||||
cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
}
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
vector<char> in_queue(n + 1, false);
|
||||
queue<int> q;
|
||||
dis[s] = 0;
|
||||
q.push(s);
|
||||
in_queue[s] = true;
|
||||
while (!q.empty()) {
|
||||
int u = q.front();
|
||||
q.pop();
|
||||
in_queue[u] = false; // 离队后仍允许再次排队
|
||||
for (const auto &e : g[u]) {
|
||||
int v = e.to;
|
||||
ll nd = dis[u] + e.w;
|
||||
if (nd < dis[v]) {
|
||||
dis[v] = nd; // 已在队列中也必须更新距离
|
||||
if (!in_queue[v]) {
|
||||
q.push(v);
|
||||
in_queue[v] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= n; ++i)
|
||||
cout << (dis[i] == INF ? 2147483647LL : dis[i])
|
||||
<< (i == n ? '\n' : ' ');
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// P4568 / 教材例 10-2:隐式分层图,最多 k 次免费。
|
||||
// n m k;s t;m 行 u v w。城市从 0 编号,无向非负边。
|
||||
// 课堂扩展约定:如果没有路线,输出 -1;原题未指定此情况的输出。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
using State = tuple<ll, int, int>;
|
||||
struct Edge { int to; ll w; };
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m, k, s, t;
|
||||
if (!(cin >> n >> m >> k >> s >> t)) return 0;
|
||||
vector<vector<Edge>> g(n);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v; ll w; cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
g[v].push_back({u, w});
|
||||
}
|
||||
const ll INF = (1LL << 60);
|
||||
vector<vector<ll>> dis(k + 1, vector<ll>(n, INF));
|
||||
priority_queue<State, vector<State>, greater<State>> q;
|
||||
dis[0][s] = 0;
|
||||
q.push({0, s, 0});
|
||||
while (!q.empty()) {
|
||||
State cur = q.top(); q.pop();
|
||||
ll d = get<0>(cur);
|
||||
int u = get<1>(cur), j = get<2>(cur);
|
||||
if (d != dis[j][u]) continue;
|
||||
for (const auto &e : g[u]) {
|
||||
int v = e.to;
|
||||
ll nd = d + e.w;
|
||||
if (nd < dis[j][v]) {
|
||||
dis[j][v] = nd;
|
||||
q.push({nd, v, j});
|
||||
}
|
||||
if (j < k && d < dis[j + 1][v]) {
|
||||
dis[j + 1][v] = d;
|
||||
q.push({d, v, j + 1});
|
||||
}
|
||||
}
|
||||
}
|
||||
ll ans = INF;
|
||||
for (int j = 0; j <= k; ++j) ans = min(ans, dis[j][t]);
|
||||
cout << (ans == INF ? -1 : ans) << '\n';
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// P1629 / 教材例 10-3:有向正权图,题目保证任意两点互相可达。
|
||||
// 输入 n m,随后 m 行 u v w;顶点从 1 编号。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
using State = pair<ll, int>;
|
||||
struct Edge { int to; ll w; };
|
||||
vector<ll> dijkstra(const vector<vector<Edge>> &g, int s) {
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(g.size(), INF);
|
||||
priority_queue<State, vector<State>, greater<State>> q;
|
||||
dis[s] = 0; q.push({0, s});
|
||||
while (!q.empty()) {
|
||||
State cur = q.top(); q.pop();
|
||||
ll d = cur.first; int u = cur.second;
|
||||
if (d != dis[u]) continue;
|
||||
for (const auto &e : g[u]) {
|
||||
ll nd = d + e.w;
|
||||
if (nd < dis[e.to]) {
|
||||
dis[e.to] = nd;
|
||||
q.push({nd, e.to});
|
||||
}
|
||||
}
|
||||
}
|
||||
return dis;
|
||||
}
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m;
|
||||
if (!(cin >> n >> m)) return 0;
|
||||
vector<vector<Edge>> g(n + 1), rg(n + 1);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v; ll w; cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
rg[v].push_back({u, w});
|
||||
}
|
||||
vector<ll> out = dijkstra(g, 1);
|
||||
vector<ll> back = dijkstra(rg, 1);
|
||||
ll ans = 0;
|
||||
for (int i = 2; i <= n; ++i) ans += out[i] + back[i];
|
||||
cout << ans << '\n';
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// 教学扩展:非负有向图,多源最短路。
|
||||
// 输入 n m r;下一行 r 个源点编号;随后 m 行 u v w。
|
||||
// 顶点编号 1..n,允许重复源点;输出到各点的最近距离,不可达输出 -1。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
using State = pair<ll, int>;
|
||||
struct Edge { int to; ll w; };
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m, r;
|
||||
if (!(cin >> n >> m >> r)) return 0;
|
||||
vector<int> sources(r);
|
||||
for (int &x : sources) cin >> x;
|
||||
vector<vector<Edge>> g(n + 1);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v; ll w; cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
}
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
priority_queue<State, vector<State>, greater<State>> q;
|
||||
for (int x : sources) {
|
||||
if (dis[x] == 0) continue;
|
||||
dis[x] = 0;
|
||||
q.push({0, x});
|
||||
}
|
||||
while (!q.empty()) {
|
||||
State cur = q.top(); q.pop();
|
||||
ll d = cur.first; int u = cur.second;
|
||||
if (d != dis[u]) continue;
|
||||
for (const auto &e : g[u]) {
|
||||
ll nd = d + e.w;
|
||||
if (nd < dis[e.to]) {
|
||||
dis[e.to] = nd;
|
||||
q.push({nd, e.to});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= n; ++i)
|
||||
cout << (dis[i] == INF ? -1 : dis[i]) << (i == n ? '\n' : ' ');
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// P3385:检测从 1 可达的负环。C++11。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
struct Edge { int v, w; };
|
||||
|
||||
bool hasNegativeCycle(const vector<vector<Edge>>& g) {
|
||||
int n = static_cast<int>(g.size()) - 1;
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
vector<int> len(n + 1, 0);
|
||||
vector<bool> inq(n + 1, false);
|
||||
queue<int> q;
|
||||
dis[1] = 0;
|
||||
q.push(1); inq[1] = true;
|
||||
while (!q.empty()) {
|
||||
int u = q.front(); q.pop();
|
||||
inq[u] = false;
|
||||
for (auto e : g[u]) {
|
||||
int v = e.v;
|
||||
ll nd = dis[u] + e.w;
|
||||
if (nd >= dis[v]) continue;
|
||||
dis[v] = nd;
|
||||
len[v] = len[u] + 1;
|
||||
if (len[v] >= n) return true;
|
||||
if (!inq[v]) {
|
||||
q.push(v);
|
||||
inq[v] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int T;
|
||||
if (!(cin >> T)) return 0;
|
||||
while (T--) {
|
||||
int n, m; cin >> n >> m;
|
||||
vector<vector<Edge>> g(n + 1);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v, w; cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
if (w >= 0) g[v].push_back({u, w});
|
||||
}
|
||||
bool bad = hasNegativeCycle(g);
|
||||
cout << (bad ? "YES" : "NO") << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// 教学版 Bellman-Ford 判环;输入格式与 P3385 一致。C++11。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
struct Edge { int u, v, w; };
|
||||
|
||||
bool hasNegativeCycle(int n, const vector<Edge>& edges, int s) {
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> dis(n + 1, INF);
|
||||
dis[s] = 0;
|
||||
for (int k = 1; k <= n; ++k) {
|
||||
auto old = dis;
|
||||
bool changed = false;
|
||||
for (auto e : edges) {
|
||||
if (old[e.u] == INF) continue;
|
||||
ll nd = old[e.u] + e.w;
|
||||
if (nd < dis[e.v]) {
|
||||
dis[e.v] = nd;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (!changed) return false;
|
||||
if (k == n) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int T;
|
||||
if (!(cin >> T)) return 0;
|
||||
while (T--) {
|
||||
int n, m; cin >> n >> m;
|
||||
vector<Edge> edges;
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int u, v, w; cin >> u >> v >> w;
|
||||
edges.push_back({u, v, w});
|
||||
if (w >= 0) edges.push_back({v, u, w});
|
||||
}
|
||||
cout << (hasNegativeCycle(n, edges, 1) ? "YES" : "NO") << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// P5960:求任意一组差分约束可行解。C++11。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
struct Edge { int v, w; };
|
||||
|
||||
bool solve(const vector<vector<Edge>>& g, vector<ll>& dis) {
|
||||
int n = static_cast<int>(g.size()) - 1;
|
||||
dis.assign(n + 1, 0);
|
||||
vector<int> len(n + 1, 0);
|
||||
vector<bool> inq(n + 1, true);
|
||||
queue<int> q;
|
||||
for (int i = 1; i <= n; ++i) q.push(i);
|
||||
while (!q.empty()) {
|
||||
int u = q.front(); q.pop();
|
||||
inq[u] = false;
|
||||
for (auto e : g[u]) {
|
||||
int v = e.v;
|
||||
ll nd = dis[u] + e.w;
|
||||
if (nd >= dis[v]) continue;
|
||||
dis[v] = nd;
|
||||
len[v] = len[u] + 1;
|
||||
if (len[v] >= n) return false;
|
||||
if (!inq[v]) {
|
||||
q.push(v); inq[v] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m;
|
||||
if (!(cin >> n >> m)) return 0;
|
||||
vector<vector<Edge>> g(n + 1);
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int a, b, w; cin >> a >> b >> w;
|
||||
g[b].push_back({a, w});
|
||||
}
|
||||
vector<ll> dis;
|
||||
if (!solve(g, dis)) cout << "NO\n";
|
||||
else {
|
||||
for (int i = 1; i <= n; ++i)
|
||||
cout << dis[i] << (i == n ? '\n' : ' ');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// P2865:正权无向图,允许重复点和边的严格次短路。C++11。
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
struct Edge { int v, w; };
|
||||
|
||||
ll secondShortest(const vector<vector<Edge>>& g) {
|
||||
int n = static_cast<int>(g.size()) - 1;
|
||||
const ll INF = (1LL << 60);
|
||||
vector<ll> d1(n + 1, INF);
|
||||
vector<ll> d2(n + 1, INF);
|
||||
using State = pair<ll, int>;
|
||||
priority_queue<State, vector<State>, greater<State>> q;
|
||||
d1[1] = 0;
|
||||
q.push({0, 1});
|
||||
while (!q.empty()) {
|
||||
State cur = q.top(); q.pop();
|
||||
ll d = cur.first;
|
||||
int u = cur.second;
|
||||
if (d != d1[u] && d != d2[u]) continue;
|
||||
for (auto e : g[u]) {
|
||||
int v = e.v;
|
||||
ll nd = d + e.w;
|
||||
if (nd < d1[v]) {
|
||||
// 新最短留下,旧最短继续竞争第二标签。
|
||||
swap(nd, d1[v]);
|
||||
q.push({d1[v], v});
|
||||
}
|
||||
if (d1[v] < nd && nd < d2[v]) {
|
||||
d2[v] = nd;
|
||||
q.push({d2[v], v});
|
||||
}
|
||||
}
|
||||
}
|
||||
return d2[n];
|
||||
}
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, r;
|
||||
if (!(cin >> n >> r)) return 0;
|
||||
vector<vector<Edge>> g(n + 1);
|
||||
for (int i = 0; i < r; ++i) {
|
||||
int u, v, w; cin >> u >> v >> w;
|
||||
g[u].push_back({v, w});
|
||||
g[v].push_back({u, w});
|
||||
}
|
||||
// 原题保证严格次短存在。
|
||||
cout << secondShortest(g) << '\n';
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// P2910:完整非负矩阵,按规定顺序访问的最小总危险值。
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
|
||||
void floyd(vector<vector<ll>>& d, int n) {
|
||||
for (int k = 1; k <= n; ++k)
|
||||
for (int i = 1; i <= n; ++i)
|
||||
for (int j = 1; j <= n; ++j)
|
||||
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
|
||||
}
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m;
|
||||
cin >> n >> m;
|
||||
vector<int> a(m);
|
||||
for (int t = 0; t < m; ++t) cin >> a[t];
|
||||
vector<vector<ll>> d(n + 1, vector<ll>(n + 1));
|
||||
for (int i = 1; i <= n; ++i)
|
||||
for (int j = 1; j <= n; ++j) cin >> d[i][j];
|
||||
floyd(d, n);
|
||||
ll ans = 0;
|
||||
for (int t = 1; t < m; ++t) ans += d[a[t - 1]][a[t]];
|
||||
cout << ans << '\n';
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// 教学模板:有向图,无负环。输入 n m,随后 m 行 u v w。
|
||||
// 输出 n 行最短距离矩阵,不可达写 INF。这个输出约定为教学自拟。
|
||||
// 建议教学数据 n<=500、|w|<=10^9,有限路长和候选之和远小于 INF。
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
const ll INF = 1LL << 60;
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, m;
|
||||
cin >> n >> m;
|
||||
vector<vector<ll>> d(n + 1, vector<ll>(n + 1, INF));
|
||||
for (int i = 1; i <= n; ++i) d[i][i] = 0;
|
||||
for (int t = 0; t < m; ++t) {
|
||||
int u, v;
|
||||
ll w;
|
||||
cin >> u >> v >> w;
|
||||
d[u][v] = min(d[u][v], w);
|
||||
}
|
||||
for (int k = 1; k <= n; ++k)
|
||||
for (int i = 1; i <= n; ++i)
|
||||
for (int j = 1; j <= n; ++j) {
|
||||
if (d[i][k] == INF || d[k][j] == INF) continue;
|
||||
ll nd = d[i][k] + d[k][j];
|
||||
d[i][j] = min(d[i][j], nd);
|
||||
}
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
for (int j = 1; j <= n; ++j) {
|
||||
if (j > 1) cout << ' ';
|
||||
if (d[i][j] == INF) cout << "INF";
|
||||
else cout << d[i][j];
|
||||
}
|
||||
cout << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// B3611:至少经过一条边的可达性,不预先把对角线设为 true。
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
bool reach[105][105]{};
|
||||
|
||||
void closure(int n) {
|
||||
for (int k = 1; k <= n; ++k)
|
||||
for (int i = 1; i <= n; ++i)
|
||||
for (int j = 1; j <= n; ++j)
|
||||
reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
|
||||
}
|
||||
|
||||
int main() {
|
||||
ios::sync_with_stdio(false);
|
||||
cin.tie(nullptr);
|
||||
int n, x;
|
||||
cin >> n;
|
||||
for (int i = 1; i <= n; ++i)
|
||||
for (int j = 1; j <= n; ++j) {
|
||||
cin >> x;
|
||||
reach[i][j] = (x != 0);
|
||||
}
|
||||
closure(n);
|
||||
for (int i = 1; i <= n; ++i)
|
||||
for (int j = 1; j <= n; ++j)
|
||||
cout << int(reach[i][j]) << (j == n ? '\n' : ' ');
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// P1144 最短路计数。C++17;无向无权图,重边按不同边计数。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m; if (!(cin >> n >> m)) return 0;
|
||||
vector<int> head(n + 1, -1), to(2 * m), nxt(2 * m);
|
||||
int tot = 0;
|
||||
auto add = [&](int u, int v) {
|
||||
to[tot] = v; nxt[tot] = head[u]; head[u] = tot++;
|
||||
};
|
||||
for (int i = 0, u, v; i < m; ++i) {
|
||||
cin >> u >> v; add(u, v); add(v, u);
|
||||
}
|
||||
vector<int> dist(n + 1, -1), ways(n + 1, 0);
|
||||
queue<int> q; dist[1] = 0; ways[1] = 1; q.push(1);
|
||||
while (!q.empty()) {
|
||||
int u = q.front(); q.pop();
|
||||
for (int e = head[u]; e != -1; e = nxt[e]) {
|
||||
int v = to[e];
|
||||
if (dist[v] == -1) {
|
||||
dist[v] = dist[u] + 1; q.push(v);
|
||||
}
|
||||
if (dist[v] == dist[u] + 1)
|
||||
ways[v] = (ways[v] + ways[u]) % 100003;
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= n; ++i) cout << ways[i] << '\n';
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// P1875 魔法药水。每个原料位置独立选择制法,交换配方书写顺序不重复计数。
|
||||
// 当前原题提示同一对原料可能有不同产物,必须保存所有不同配方。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
ll addSat(ll a, ll b) { return a > LLONG_MAX - b ? LLONG_MAX : a + b; }
|
||||
ll mulSat(ll a, ll b) {
|
||||
if (a == 0 || b == 0) return 0;
|
||||
return a > LLONG_MAX / b ? LLONG_MAX : a * b;
|
||||
}
|
||||
struct Recipe { int a, b, c; };
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n; if (!(cin >> n)) return 0;
|
||||
vector<ll> d(n), ways(n, 1);
|
||||
for (ll &x : d) cin >> x;
|
||||
vector<Recipe> rec;
|
||||
vector<vector<int>> incident(n);
|
||||
unordered_set<ll> seen;
|
||||
int a, b, c;
|
||||
while (cin >> a >> b >> c) {
|
||||
if (a > b) swap(a, b);
|
||||
ll key = (1LL * a * n + b) * n + c;
|
||||
if (!seen.insert(key).second) continue;
|
||||
int id = (int)rec.size(); rec.push_back({a, b, c});
|
||||
incident[a].push_back(id); incident[b].push_back(id);
|
||||
}
|
||||
vector<int> need(rec.size(), 2);
|
||||
vector<bool> done(n, false);
|
||||
for (int round = 0; round < n; ++round) {
|
||||
int u = -1;
|
||||
for (int i = 0; i < n; ++i)
|
||||
if (!done[i] && (u == -1 || d[i] < d[u])) u = i;
|
||||
done[u] = true;
|
||||
for (int id : incident[u]) {
|
||||
if (--need[id] != 0) continue;
|
||||
auto [a, b, c] = rec[id];
|
||||
ll nd = d[a] + d[b], cnt = mulSat(ways[a], ways[b]);
|
||||
if (nd < d[c]) { d[c] = nd; ways[c] = cnt; }
|
||||
else if (nd == d[c]) ways[c] = addSat(ways[c], cnt);
|
||||
}
|
||||
}
|
||||
cout << d[0] << ' ' << ways[0] << '\n';
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// P1462 通往奥格瑞玛的道路。城市费二分,非负道路耗血用 Dijkstra。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m; ll b; if (!(cin >> n >> m >> b)) return 0;
|
||||
vector<int> fee(n + 1), values;
|
||||
for (int i = 1; i <= n; ++i) { cin >> fee[i]; values.push_back(fee[i]); }
|
||||
vector<vector<pair<int,ll>>> g(n + 1);
|
||||
for (int i = 0, u, v; i < m; ++i) {
|
||||
ll w; cin >> u >> v >> w;
|
||||
g[u].push_back({v,w}); g[v].push_back({u,w});
|
||||
}
|
||||
auto check = [&](int X) {
|
||||
if (fee[1] > X || fee[n] > X) return false;
|
||||
const ll INF = 1LL << 60;
|
||||
vector<ll> dist(n + 1, INF);
|
||||
priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;
|
||||
dist[1] = 0; pq.push({0,1});
|
||||
while (!pq.empty()) {
|
||||
auto [du,u] = pq.top(); pq.pop();
|
||||
if (du != dist[u]) continue;
|
||||
for (auto [v,w] : g[u]) {
|
||||
if (fee[v] > X) continue;
|
||||
if (du + w < dist[v]) {
|
||||
dist[v] = du + w; pq.push({dist[v],v});
|
||||
}
|
||||
}
|
||||
}
|
||||
return dist[n] <= b;
|
||||
};
|
||||
sort(values.begin(), values.end());
|
||||
values.erase(unique(values.begin(), values.end()), values.end());
|
||||
if (!check(values.back())) { cout << "AFK\n"; return 0; }
|
||||
int l = 0, r = (int)values.size() - 1;
|
||||
while (l < r) {
|
||||
int mid = l + (r-l)/2;
|
||||
if (check(values[mid])) r = mid; else l = mid + 1;
|
||||
}
|
||||
cout << values[l] << '\n';
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// P1073 最优贸易。价格是 1..100,单调标签至多改善 100 次。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m; if (!(cin >> n >> m)) return 0;
|
||||
vector<int> price(n + 1);
|
||||
for (int i = 1; i <= n; ++i) cin >> price[i];
|
||||
vector<vector<int>> g(n + 1), rg(n + 1);
|
||||
auto add = [&](int u, int v) { g[u].push_back(v); rg[v].push_back(u); };
|
||||
for (int i = 0, u, v, z; i < m; ++i) {
|
||||
cin >> u >> v >> z; add(u,v); if (z == 2) add(v,u);
|
||||
}
|
||||
vector<int> low(n + 1, 101), high(n + 1, -1);
|
||||
vector<bool> inq(n + 1, false);
|
||||
queue<int> q; low[1] = price[1]; q.push(1); inq[1] = true;
|
||||
while (!q.empty()) {
|
||||
int u = q.front(); q.pop(); inq[u] = false;
|
||||
for (int v : g[u]) {
|
||||
int cand = min(low[u], price[v]);
|
||||
if (cand < low[v]) {
|
||||
low[v] = cand;
|
||||
if (!inq[v]) { q.push(v); inq[v] = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
high[n] = price[n]; q.push(n); inq[n] = true;
|
||||
while (!q.empty()) {
|
||||
int u = q.front(); q.pop(); inq[u] = false;
|
||||
for (int v : rg[u]) {
|
||||
int cand = max(high[u], price[v]);
|
||||
if (cand > high[v]) {
|
||||
high[v] = cand;
|
||||
if (!inq[v]) { q.push(v); inq[v] = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
int ans = 0;
|
||||
for (int v = 1; v <= n; ++v)
|
||||
if (low[v] <= 100 && high[v] >= 1) ans = max(ans, high[v]-low[v]);
|
||||
cout << ans << '\n';
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// P1993 小K的农场。上界边 x[v] <= x[u]+w,全图判负环。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m; if (!(cin >> n >> m)) return 0;
|
||||
vector<vector<pair<int,ll>>> g(n + 1);
|
||||
auto add = [&](int u, int v, ll w) { g[u].push_back({v,w}); };
|
||||
for (int i = 0, type, a, b; i < m; ++i) {
|
||||
cin >> type >> a >> b; ll c;
|
||||
if (type == 1) { cin >> c; add(a,b,-c); }
|
||||
else if (type == 2) { cin >> c; add(b,a,c); }
|
||||
else { add(a,b,0); add(b,a,0); }
|
||||
}
|
||||
vector<ll> dist(n + 1, 0);
|
||||
vector<int> len(n + 1, 0);
|
||||
vector<bool> inq(n + 1, true);
|
||||
queue<int> q; for (int i = 1; i <= n; ++i) q.push(i);
|
||||
while (!q.empty()) {
|
||||
int u = q.front(); q.pop(); inq[u] = false;
|
||||
for (auto [v,w] : g[u]) if (dist[v] > dist[u] + w) {
|
||||
dist[v] = dist[u] + w; len[v] = len[u] + 1;
|
||||
if (len[v] >= n) { cout << "No\n"; return 0; }
|
||||
if (!inq[v]) { q.push(v); inq[v] = true; }
|
||||
}
|
||||
}
|
||||
cout << "Yes\n";
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// P3275 糖果。迭代 Kosaraju + 缩点 DAG 上的最长下界,O(n+k)。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, k; if (!(cin >> n >> k)) return 0;
|
||||
vector<vector<pair<int,int>>> g(n);
|
||||
vector<vector<int>> rg(n);
|
||||
auto add = [&](int u, int v, int w) { g[u].push_back({v,w}); rg[v].push_back(u); };
|
||||
for (int i = 0, x, a, b; i < k; ++i) {
|
||||
cin >> x >> a >> b; --a; --b;
|
||||
if (x == 1) { add(a,b,0); add(b,a,0); }
|
||||
if (x == 2) add(a,b,1);
|
||||
if (x == 3) add(b,a,0);
|
||||
if (x == 4) add(b,a,1);
|
||||
if (x == 5) add(a,b,0);
|
||||
}
|
||||
vector<bool> vis(n, false);
|
||||
vector<int> order;
|
||||
// 第一次 DFS:显式保存下一条边下标,退出时记录结束序。
|
||||
for (int s = 0; s < n; ++s) if (!vis[s]) {
|
||||
vector<pair<int,int>> st;
|
||||
vis[s] = true; st.push_back({s,0});
|
||||
while (!st.empty()) {
|
||||
auto &[u,i] = st.back();
|
||||
if (i == (int)g[u].size()) { order.push_back(u); st.pop_back(); }
|
||||
else {
|
||||
int v = g[u][i++].first;
|
||||
if (!vis[v]) { vis[v] = true; st.push_back({v,0}); }
|
||||
}
|
||||
}
|
||||
}
|
||||
// 第二次 DFS:反图按逆结束序分组。
|
||||
vector<int> comp(n, -1), size;
|
||||
int count = 0;
|
||||
reverse(order.begin(), order.end());
|
||||
for (int s : order) if (comp[s] == -1) {
|
||||
vector<int> st(1,s); comp[s] = count; int amount = 0;
|
||||
while (!st.empty()) {
|
||||
int u = st.back(); st.pop_back(); ++amount;
|
||||
for (int v : rg[u]) if (comp[v] == -1) {
|
||||
comp[v] = count; st.push_back(v);
|
||||
}
|
||||
}
|
||||
size.push_back(amount); ++count;
|
||||
}
|
||||
vector<vector<pair<int,int>>> dag(count);
|
||||
vector<int> indeg(count, 0), d(count, 1);
|
||||
for (int u = 0; u < n; ++u) for (auto [v,w] : g[u]) {
|
||||
if (comp[u] == comp[v]) {
|
||||
if (w == 1) { cout << -1 << '\n'; return 0; }
|
||||
} else {
|
||||
dag[comp[u]].push_back({comp[v],w}); ++indeg[comp[v]];
|
||||
}
|
||||
}
|
||||
queue<int> q;
|
||||
for (int c = 0; c < count; ++c) if (indeg[c] == 0) q.push(c);
|
||||
while (!q.empty()) {
|
||||
int u = q.front(); q.pop();
|
||||
for (auto [v,w] : dag[u]) {
|
||||
d[v] = max(d[v], d[u]+w);
|
||||
if (--indeg[v] == 0) q.push(v);
|
||||
}
|
||||
}
|
||||
long long ans = 0;
|
||||
for (int c = 0; c < count; ++c) ans += 1LL * size[c] * d[c];
|
||||
cout << ans << '\n';
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// P6464 传送门。原图 Floyd 一次,独立枚举一对零边。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m; if (!(cin >> n >> m)) return 0;
|
||||
const ll INF = 1LL << 60;
|
||||
vector<vector<ll>> d(n, vector<ll>(n, INF));
|
||||
for (int i = 0; i < n; ++i) d[i][i] = 0;
|
||||
for (int e = 0, u, v; e < m; ++e) {
|
||||
ll w; cin >> u >> v >> w; --u; --v;
|
||||
d[u][v] = d[v][u] = min(d[u][v], w);
|
||||
}
|
||||
for (int k = 0; k < n; ++k)
|
||||
for (int i = 0; i < n; ++i)
|
||||
for (int j = 0; j < n; ++j)
|
||||
if (d[i][k] != INF && d[k][j] != INF)
|
||||
d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
|
||||
ll ans = 0;
|
||||
for (int i = 0; i < n; ++i) for (int j = i+1; j < n; ++j) ans += d[i][j];
|
||||
for (int u = 0; u < n; ++u) for (int v = u+1; v < n; ++v) {
|
||||
ll sum = 0;
|
||||
for (int i = 0; i < n; ++i) for (int j = i+1; j < n; ++j)
|
||||
sum += min({d[i][j], d[i][u]+d[v][j], d[i][v]+d[u][j]});
|
||||
ans = min(ans, sum);
|
||||
}
|
||||
cout << ans << '\n';
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// P3403 跳楼机。楼层减一,按最小步长的余数建图。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
ll h; array<int,3> step;
|
||||
if (!(cin >> h >> step[0] >> step[1] >> step[2])) return 0;
|
||||
sort(step.begin(), step.end()); int m = step[0];
|
||||
const ll INF = 1LL << 60;
|
||||
vector<ll> d(m, INF);
|
||||
priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;
|
||||
d[0] = 0; pq.push({0,0});
|
||||
while (!pq.empty()) {
|
||||
auto [du,u] = pq.top(); pq.pop();
|
||||
if (du != d[u]) continue;
|
||||
for (int i = 1; i <= 2; ++i) {
|
||||
int w = step[i], v = (u+w)%m;
|
||||
if (du + w < d[v]) { d[v] = du+w; pq.push({d[v],v}); }
|
||||
}
|
||||
}
|
||||
ll L = h-1, ans = 0;
|
||||
for (int r = 0; r < m; ++r) {
|
||||
if (d[r] == INF || d[r] > L) continue;
|
||||
ans += (L-d[r])/m + 1;
|
||||
}
|
||||
cout << ans << '\n';
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// P1119 灾后重建。原题编号 0..n-1,重建时间和询问时间分别不下降。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m; if (!(cin >> n >> m)) return 0;
|
||||
vector<int> repair(n); for (int &t : repair) cin >> t;
|
||||
const ll INF = 1LL << 60;
|
||||
vector<vector<ll>> d(n, vector<ll>(n, INF));
|
||||
for (int i = 0; i < n; ++i) d[i][i] = 0;
|
||||
for (int e = 0, u, v; e < m; ++e) {
|
||||
ll w; cin >> u >> v >> w; d[u][v] = d[v][u] = min(d[u][v],w);
|
||||
}
|
||||
int Q, k = 0; cin >> Q;
|
||||
while (Q--) {
|
||||
int x, y, t; cin >> x >> y >> t;
|
||||
while (k < n && repair[k] <= t) {
|
||||
for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) {
|
||||
if (d[i][k] == INF || d[k][j] == INF) continue;
|
||||
d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
|
||||
}
|
||||
++k;
|
||||
}
|
||||
if (repair[x] > t || repair[y] > t || d[x][y] == INF) cout << -1 << '\n';
|
||||
else cout << d[x][y] << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// P1037 产生数。十个数字的自反传递闭包 + 十进制高精度乘法。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
string mulSmall(string s, int k) {
|
||||
int carry = 0;
|
||||
for (int i = (int)s.size()-1; i >= 0; --i) {
|
||||
int t = (s[i]-'0')*k + carry;
|
||||
s[i] = char('0'+t%10); carry = t/10;
|
||||
}
|
||||
while (carry) { s.insert(s.begin(), char('0'+carry%10)); carry /= 10; }
|
||||
return s;
|
||||
}
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
string number; int k; if (!(cin >> number >> k)) return 0;
|
||||
bool reach[10][10] = {};
|
||||
for (int i = 0; i < 10; ++i) reach[i][i] = true;
|
||||
for (int i = 0, a, b; i < k; ++i) { cin >> a >> b; reach[a][b] = true; }
|
||||
for (int mid = 0; mid < 10; ++mid)
|
||||
for (int i = 0; i < 10; ++i)
|
||||
for (int j = 0; j < 10; ++j)
|
||||
reach[i][j] |= reach[i][mid] && reach[mid][j];
|
||||
int choices[10] = {};
|
||||
for (int a = 0; a < 10; ++a) for (int b = 0; b < 10; ++b) choices[a] += reach[a][b];
|
||||
string ans = "1";
|
||||
for (char digit : number) ans = mulSmall(ans, choices[digit-'0']);
|
||||
cout << ans << '\n';
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// P2419 牛大赛。胜者指向败者,闭包后判断是否与其余点全部可比较。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m; if (!(cin >> n >> m)) return 0;
|
||||
vector<vector<bool>> reach(n, vector<bool>(n, false));
|
||||
for (int i = 0, a, b; i < m; ++i) { cin >> a >> b; reach[a-1][b-1] = true; }
|
||||
for (int k = 0; k < n; ++k) for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j)
|
||||
reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
|
||||
int ans = 0;
|
||||
for (int v = 0; v < n; ++v) {
|
||||
int known = 0;
|
||||
for (int j = 0; j < n; ++j) {
|
||||
if (j == v) continue;
|
||||
if (reach[v][j] || reach[j][v]) ++known;
|
||||
}
|
||||
if (known == n-1) ++ans;
|
||||
}
|
||||
cout << ans << '\n';
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// P2047 社交网络。正权、无向、简单、连通图;有序点对,排除端点。
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
int main() {
|
||||
ios::sync_with_stdio(false); cin.tie(nullptr);
|
||||
int n, m; if (!(cin >> n >> m)) return 0;
|
||||
const ll INF = 1LL << 60;
|
||||
vector<vector<ll>> d(n, vector<ll>(n, INF));
|
||||
// 中间受限图的计数可能超过最终答案范围,从存储起即用浮点。
|
||||
vector<vector<long double>> cnt(n, vector<long double>(n, 0));
|
||||
for (int i = 0; i < n; ++i) d[i][i] = 0;
|
||||
for (int e = 0, u, v; e < m; ++e) {
|
||||
ll w; cin >> u >> v >> w; --u; --v;
|
||||
d[u][v] = d[v][u] = w; cnt[u][v] = cnt[v][u] = 1;
|
||||
}
|
||||
for (int k = 0; k < n; ++k) for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) {
|
||||
if (i == k || j == k || i == j) continue;
|
||||
if (d[i][k] == INF || d[k][j] == INF) continue;
|
||||
ll nd = d[i][k]+d[k][j];
|
||||
long double ways = cnt[i][k]*cnt[k][j];
|
||||
if (nd < d[i][j]) { d[i][j] = nd; cnt[i][j] = ways; }
|
||||
else if (nd == d[i][j]) cnt[i][j] += ways;
|
||||
}
|
||||
cout << fixed << setprecision(3);
|
||||
for (int v = 0; v < n; ++v) {
|
||||
long double ans = 0;
|
||||
for (int s = 0; s < n; ++s) for (int t = 0; t < n; ++t) {
|
||||
if (s == t || s == v || t == v) continue;
|
||||
if (d[s][v]+d[v][t] == d[s][t]) ans += cnt[s][v]*cnt[v][t]/cnt[s][t];
|
||||
}
|
||||
cout << ans << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# 源码说明
|
||||
|
||||
共 28 份独立完整程序。建议全部按 GCC C++17 编译。每个文件含独立 `main`,应单独编译。输入来自标准输入,结果写到标准输出。
|
||||
|
||||
## 前六份课件
|
||||
|
||||
| 文件 | 对应内容 | 输入与输出约定 |
|
||||
| --- | --- | --- |
|
||||
| 01_dijkstra_naive.cpp | P3371,邻接表朴素 Dijkstra | n m s;m 条有向边;输出源点到各点距离 |
|
||||
| 01b_dijkstra_forward_star.cpp | P3371,前向星朴素 Dijkstra | 同上;改变存图方式 |
|
||||
| 01c_dijkstra_path.cpp | 第一章路径恢复扩展 | 教学输入格式与路径输出见源码注释及第一章备注 |
|
||||
| 02_dijkstra_heap.cpp | P3371,堆优化 Dijkstra | 同上;非负边权 |
|
||||
| 02b_bellman_ford.cpp | 备份版 Bellman–Ford | 同 P3371 输入输出;教学扩展允许负边,无源点可达负环 |
|
||||
| 02c_spfa.cpp | FIFO SPFA | 同上;此版不带判环,最坏 O(nm) |
|
||||
| 03_flights.cpp | P4568,分层状态 | n m k;s t;m 条无向边;0 开始编号;不可达输出 -1 是教学扩展约定 |
|
||||
| 03b_postman.cpp | P1629,反图与往返 | n m;m 条有向边;1 开始编号;按原题保证各点互达 |
|
||||
| 03c_multi_source.cpp | 多源最短路教学扩展 | n m r;r 个源点;m 条有向边;不可达输出 -1 |
|
||||
| 04_negative_cycle.cpp | P3385,SPFA 判环 | 多组数据;仅检测从 1 可达的负环;非负输入边双向、负边单向 |
|
||||
| 04a_bf_negative.cpp | P3385,Bellman–Ford 判环 | 同上一文件 |
|
||||
| 04b_difference_constraints.cpp | P5960,差分约束 | a b c 表示 x[a]−x[b]≤c;输出任意解,无解为 NO |
|
||||
| 05_second_shortest.cpp | P2865,严格次短路 | 正权无向图;允许重复经过点边,第二距离严格大于最短距离 |
|
||||
| 06_floyd_trip.cpp | P2910,规定访问顺序 | 读入访问序列和完整危险值矩阵,输出最小总危险值 |
|
||||
| 06a_floyd_general.cpp | 通用 Floyd 教学模板 | n m;m 条有向边;无负环;输出矩阵,不可达为 INF |
|
||||
| 06b_transitive_closure.cpp | B3611,非空路径闭包 | 输入邻接矩阵;不预先把对角线设为真 |
|
||||
|
||||
P3371 系列程序以 2147483647 表示不可达。通用 Floyd 教学模板建议 n≤500、边权绝对值≤10^9,确保所选 INF 和 `long long` 有足够余量。
|
||||
|
||||
## 综合习题的重要前提
|
||||
|
||||
`07_01_p1144.cpp` 至 `07_12_p2047.cpp` 与课程使用说明的 12 道习题一一对应,输入输出遵循相应题号。
|
||||
|
||||
- P1144:重边按不同边计数,模 100003。
|
||||
- P1875:配方读到 EOF;保存同一原料对的不同产物,完全重复的无序配方去重。主算法 O(n²+R),哈希去重的 O(R) 是期望复杂度。无关药水极大中间计数采用饱和运算,原题承诺范围内的目标答案保持精确。
|
||||
- P1462:费用包括起终点,耗血恰好等于初始血量仍可行。
|
||||
- P1073:传播次数的界依赖价格范围 1…100。
|
||||
- P1993:全图判定约束可行性,所有点一起初始化。
|
||||
- P3275:非递归强连通分量与缩点,避免深链递归栈溢出;总量用 `long long`。
|
||||
- P6464:每次试装传送门都读取原图 Floyd 距离。
|
||||
- P3403:从第 1 层开始计数,先排除不可达再计数,覆盖 h=2^63−1 边界。
|
||||
- P1119:依赖原题重建时间、询问时间分别不降的保证;0 开始编号。
|
||||
- P1037:允许零次变换,对角线置真;按最终数字去重,使用十进制高精度字符串。
|
||||
- P2419:原题胜负关系无矛盾,检查是否与其余所有点可比较。
|
||||
- P2047:正权简单无向图;有序点对双向累计并排除端点,使用 `long double` 计数与求比例,输出三位小数。
|
||||
|
||||
## 验证
|
||||
|
||||
本次以 C++17 重新编译第 2—7 章的 25 份程序,31 组新增教学输入及关键边界检查全部通过。输入输出见 `../教学样例/样例清单.json`,对应记录见 `../资料与核查/修订样例验证.json`。
|
||||
|
||||
第一章 3 份程序的修订验证记录另见 `../资料与核查/第一章程序核查.json`。旧版 27 份程序累计 3,972 组本地对照记录保留在 `../资料与核查/旧版程序验证`,本次没有重复执行全部历史测试。
|
||||
|
||||
所有验证均为本地编译运行,没有向在线评测提交。
|
||||
Binary file not shown.
Reference in new issue
Block a user