feat: new graph problems formatted.

This commit is contained in:
2026-08-24 14:47:58 -03:00
parent 5316029272
commit f89d4158cd
443 changed files with 2218170 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
#include <bits/stdc++.h>
#define INF 0x7FFFFFFF
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
using graph = vector<vector<pll>>;
const int MAXN = 510;
vector<ll> dijk(int x, graph& g) {
priority_queue<pll> pq;
pq.push({0, x});
vector<ll> dist(MAXN, INF);
while (pq.size()){
auto [w, v] = pq.top();
pq.pop();
w = -w;
if (dist[v] <= w) continue;
dist[v] = w;
for (auto [u, ww] : g[v]) {
if (dist[u] <= w + ww) continue;
pq.push({-(w+ww), u});
}
}
return dist;
}
ll almost_dijk(int s, int d, graph& g, vector<ll>& dist_s, vector<ll>& dist_d) {
ll best = dist_s[d];
if (best == INF) return -1;
priority_queue<pll> pq;
pq.push({0, s});
vector<ll> dist(MAXN, INF);
while (pq.size()){
auto [w, v] = pq.top();
pq.pop();
w = -w;
if (v == d) return w;
if (dist[v] <= w) continue;
dist[v] = w;
for (auto [u, ww] : g[v]) {
if (dist_s[v] + ww + dist_d[u] <= best) continue; // pula essa aresta, corresponde a um caminho minimo
if (dist[u] <= w + ww) continue;
pq.push({-(w+ww), u});
}
}
return -1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int n, m;
while (cin>>n>>m, n!=0 && m!=0){
int s, d; cin >> s >> d;
vector<vector<pll>> g(MAXN);
vector<vector<pll>> g_rev(MAXN);
for (int i=0;i<m;i++){
int u,v,p; cin >> u >> v >> p;
g[u].push_back({v, p});
g_rev[v].push_back({u, p});
}
vector<ll> dist_s = dijk(s, g);
vector<ll> dist_d = dijk(d, g_rev);
cout << almost_dijk(s, d, g, dist_s, dist_d) << '\n';
}
}

View File

@@ -0,0 +1,84 @@
import heapq
import sys
INF = 10**30
def dijkstra(start, graph, edges, removed):
dist = [INF] * len(graph)
dist[start] = 0
pq = [(0, start)]
while pq:
cur_dist, u = heapq.heappop(pq)
if cur_dist != dist[u]:
continue
for edge_id in graph[u]:
if removed[edge_id]:
continue
_, v, weight = edges[edge_id]
new_dist = cur_dist + weight
if new_dist < dist[v]:
dist[v] = new_dist
heapq.heappush(pq, (new_dist, v))
return dist
def solve(data):
it = iter(map(int, data.split()))
answers = []
while True:
n = next(it)
m = next(it)
if n == 0 and m == 0:
break
source = next(it)
target = next(it)
edges = []
graph = [[] for _ in range(n)]
reverse_graph = [[] for _ in range(n)]
for edge_id in range(m):
u = next(it)
v = next(it)
weight = next(it)
edges.append((u, v, weight))
graph[u].append(edge_id)
reverse_graph[v].append(edge_id)
removed = [False] * m
from_source = dijkstra(source, graph, edges, removed)
if from_source[target] == INF:
answers.append("-1")
continue
reverse_edges = [(v, u, w) for u, v, w in edges]
to_target = dijkstra(target, reverse_graph, reverse_edges, removed)
shortest = from_source[target]
for edge_id, (u, v, weight) in enumerate(edges):
if from_source[u] == INF or to_target[v] == INF:
continue
if from_source[u] + weight + to_target[v] == shortest:
removed[edge_id] = True
almost = dijkstra(source, graph, edges, removed)
answers.append(str(-1 if almost[target] == INF else almost[target]))
return "\n".join(answers)
def main():
output = solve(sys.stdin.read())
if output:
sys.stdout.write(output + "\n")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,39 @@
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char* argv[]) {
setName("compare almost shortest path length");
registerTestlibCmd(argc, argv);
int cases = 0;
while (true) {
int n = inf.readInt();
int m = inf.readInt();
if (n == 0 && m == 0) break;
cases++;
inf.readInt();
inf.readInt();
for (int i = 0; i < m; i++) {
inf.readInt();
inf.readInt();
inf.readInt();
}
int expected = ans.readInt(-1, 1000000000, "expected_answer");
int found = ouf.readInt(-1, 1000000000, "participant_answer");
if (expected != found)
quitf(_wa, "case %d: expected %d, found %d", cases, expected, found);
}
if (!ouf.seekEof())
quitf(_wa, "extra output after case %d", cases);
quitf(_ok, "all %d cases are correct", cases);
return 0;
}

View File

@@ -0,0 +1,306 @@
#include "jngen.h"
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 500;
const int MAX_M = 10000;
const int MAX_W = 1000;
const int RANDOM_FILES = 35;
struct Edge {
int u;
int v;
int w;
};
struct Case {
int n;
int source;
int target;
vector<Edge> edges;
};
template <typename T>
void append(vector<T>& dest, const vector<T>& orig) {
dest.insert(dest.end(), orig.begin(), orig.end());
}
string render_file(const vector<Case>& cases) {
ostringstream oss;
for (const Case& tc : cases) {
oss << tc.n << " " << tc.edges.size() << "\n";
oss << tc.source << " " << tc.target << "\n";
for (const Edge& e : tc.edges) {
oss << e.u << " " << e.v << " " << e.w << "\n";
}
}
oss << "0 0\n";
return oss.str();
}
void add_edge(vector<Edge>& edges, set<pair<int, int>>& used, int u, int v, int w) {
if (u == v) return;
if (!used.insert({u, v}).second) return;
edges.push_back({u, v, w});
}
Case make_case(int n, int source, int target, vector<Edge> edges) {
return {n, source, target, edges};
}
Case make_layered_case(int n, int extra_edges) {
int source = 0;
int target = n - 1;
vector<Edge> edges;
set<pair<int, int>> used;
int a = 1;
int b = max(2, n / 3);
int c = max(b + 1, 2 * n / 3);
if (c >= target) c = target - 1;
add_edge(edges, used, source, a, 1);
add_edge(edges, used, source, b, 1);
add_edge(edges, used, a, c, 2);
add_edge(edges, used, b, c, 2);
add_edge(edges, used, c, target, 2);
add_edge(edges, used, source, target, 8);
add_edge(edges, used, source, c, 6);
add_edge(edges, used, a, target, 7);
Graph g = Graph::random(n, min(extra_edges, n * (n - 1))).directed().allowAntiparallel();
for (auto p : g.edges()) {
add_edge(edges, used, p.first, p.second, rnd.next(4, MAX_W));
if ((int)edges.size() >= MAX_M) break;
}
return make_case(n, source, target, edges);
}
Case make_no_path_case(int n, int extra_edges) {
int source = 0;
int target = n - 1;
vector<Edge> edges;
set<pair<int, int>> used;
int split = max(1, n / 2);
for (int i = 0; i < extra_edges; i++) {
int u, v;
if (rnd.next(0, 1)) {
u = rnd.next(0, split - 1);
v = rnd.next(0, split - 1);
} else {
u = rnd.next(split, n - 1);
v = rnd.next(split, n - 1);
}
add_edge(edges, used, u, v, rnd.next(1, MAX_W));
}
if (edges.empty()) add_edge(edges, used, source, min(1, n - 1), 1);
return make_case(n, source, target, edges);
}
Case make_unique_second_case(int n) {
int source = 0;
int target = n - 1;
vector<Edge> edges;
set<pair<int, int>> used;
for (int i = 0; i + 1 < n; i++) {
add_edge(edges, used, i, i + 1, 1);
}
add_edge(edges, used, source, target, n + 3);
if (n > 3) {
add_edge(edges, used, source, 2, 3);
add_edge(edges, used, 2, target, n);
}
return make_case(n, source, target, edges);
}
Case make_random_case(int n, int m) {
int source = rnd.next(0, n - 1);
int target = rnd.next(0, n - 2);
if (target >= source) target++;
vector<Edge> edges;
set<pair<int, int>> used;
int chain_len = rnd.next(2, min(n, 20));
vector<int> vertices = {source};
vector<int> pool;
for (int v = 0; v < n; v++) {
if (v != source && v != target) pool.push_back(v);
}
shuffle(pool.begin(), pool.end());
for (int i = 0; i < chain_len - 2 && i < (int)pool.size(); i++) {
vertices.push_back(pool[i]);
}
vertices.push_back(target);
for (int i = 0; i + 1 < (int)vertices.size(); i++) {
add_edge(edges, used, vertices[i], vertices[i + 1], rnd.next(1, 20));
}
Graph g = Graph::random(n, min(m, n * (n - 1))).directed().allowAntiparallel();
for (auto p : g.edges()) {
add_edge(edges, used, p.first, p.second, rnd.next(1, MAX_W));
if ((int)edges.size() >= m) break;
}
while ((int)edges.size() < m) {
int u = rnd.next(0, n - 1);
int v = rnd.next(0, n - 1);
add_edge(edges, used, u, v, rnd.next(1, MAX_W));
}
return make_case(n, source, target, edges);
}
vector<string> generate_sample_tests() {
vector<string> tests;
tests.push_back(
"7 9\n"
"0 6\n"
"0 1 1\n"
"0 2 1\n"
"0 3 2\n"
"0 4 3\n"
"1 5 2\n"
"2 6 4\n"
"3 6 2\n"
"4 6 4\n"
"5 6 1\n"
"4 6\n"
"0 2\n"
"0 1 1\n"
"1 2 1\n"
"1 3 1\n"
"3 2 1\n"
"2 0 3\n"
"3 0 2\n"
"6 8\n"
"0 1\n"
"0 1 1\n"
"0 2 2\n"
"0 3 3\n"
"2 5 3\n"
"3 4 2\n"
"4 1 1\n"
"5 1 1\n"
"3 0 1\n"
"0 0\n"
);
return tests;
}
vector<string> generate_manual_tests() {
vector<string> tests;
tests.push_back(render_file({
make_case(2, 0, 1, {{0, 1, 7}}),
make_case(3, 0, 2, {{0, 1, 1}, {1, 2, 1}, {0, 2, 3}}),
make_case(4, 0, 3, {{0, 1, 1}, {1, 3, 1}, {0, 2, 1}, {2, 3, 1}}),
}));
tests.push_back(render_file({
make_layered_case(8, 12),
make_no_path_case(10, 18),
make_unique_second_case(12),
}));
tests.push_back(render_file({
make_case(5, 0, 4, {
{0, 1, 1}, {1, 4, 2}, {0, 2, 1}, {2, 4, 2},
{0, 3, 4}, {3, 4, 1}, {1, 3, 10}, {2, 3, 10}
}),
make_case(6, 5, 0, {
{5, 1, 2}, {1, 0, 2}, {5, 2, 2}, {2, 0, 2},
{5, 3, 5}, {3, 4, 1}, {4, 0, 1}
}),
}));
return tests;
}
vector<string> generate_random_tests() {
vector<string> tests;
for (int i = 0; i < RANDOM_FILES; i++) {
int cases = rnd.next(1, i < 10 ? 8 : 4);
vector<Case> data;
for (int c = 0; c < cases; c++) {
int max_n = 40;
if (i > RANDOM_FILES / 3) max_n = 120;
if (i > 2 * RANDOM_FILES / 3) max_n = 300;
int n = rnd.next(2, max_n);
int max_m = min(MAX_M, n * (n - 1));
int m = rnd.next(1, max_m);
int style = rnd.next(0, 4);
if (style == 0) {
data.push_back(make_random_case(n, m));
} else if (style == 1) {
data.push_back(make_layered_case(max(4, n), m));
} else if (style == 2) {
data.push_back(make_no_path_case(n, m));
} else {
data.push_back(make_unique_second_case(n));
}
}
tests.push_back(render_file(data));
}
return tests;
}
vector<string> generate_extreme_tests() {
vector<string> tests;
tests.push_back(render_file({
make_random_case(MAX_N, MAX_M),
}));
tests.push_back(render_file({
make_layered_case(MAX_N, MAX_M),
}));
tests.push_back(render_file({
make_no_path_case(MAX_N, MAX_M),
}));
vector<Case> many;
for (int i = 0; i < 100; i++) {
int n = rnd.next(2, 30);
int m = rnd.next(1, min(100, n * (n - 1)));
many.push_back(make_random_case(n, m));
}
tests.push_back(render_file(many));
return tests;
}
int main(int argc, char* argv[]) {
registerGen(argc, argv, 1);
vector<string> tests;
size_t test = 0;
append(tests, generate_sample_tests());
append(tests, generate_manual_tests());
append(tests, generate_random_tests());
append(tests, generate_extreme_tests());
for (const string& t : tests) {
startTest(++test);
cout << t;
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
generator

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;
const int MIN_N = 2;
const int MAX_N = 500;
const int MIN_M = 1;
const int MAX_M = 10000;
const int MIN_W = 1;
const int MAX_W = 1000;
int main(int argc, char* argv[]) {
registerValidation(argc, argv);
while (true) {
int n = inf.readInt(0, MAX_N, "N");
inf.readSpace();
int m = inf.readInt(0, MAX_M, "M");
inf.readEoln();
if (n == 0 && m == 0) break;
ensuref(n >= MIN_N, "N must be at least 2");
ensuref(m >= MIN_M, "M must be at least 1");
ensuref(m <= n * (n - 1), "Too many directed edges for a simple digraph");
int source = inf.readInt(0, n - 1, "S");
inf.readSpace();
int target = inf.readInt(0, n - 1, "D");
inf.readEoln();
ensuref(source != target, "S and D must be different");
set<pair<int, int>> used;
for (int i = 0; i < m; i++) {
int u = inf.readInt(0, n - 1, "U");
inf.readSpace();
int v = inf.readInt(0, n - 1, "V");
inf.readSpace();
inf.readInt(MIN_W, MAX_W, "P");
inf.readEoln();
ensuref(u != v, "Loops are not allowed");
ensuref(used.insert({u, v}).second, "Duplicate directed edge %d -> %d", u, v);
}
}
inf.readEof();
return 0;
}