Submission #1292657

#TimeUsernameProblemLanguageResultExecution timeMemory
1292657LucaDantas시간이 돈 (balkan11_timeismoney)C++17
100 / 100
290 ms1092 KiB
// AI Generated code for testing if it's right, I already solved it before a few years ago but I wanted to see if AI could solve it /* * Problem: Time is Money (Balkan Olympiad in Informatics 2011) * Method: Primal-Dual / Geometry on Convex Hull * Complexity: O(K * M * alpha(N)), where K is the number of hull vertices (usually small) */ #include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std; // Data structures struct Edge { int u, v, t, c, id; }; struct Point { long long x, y; // x = sumTime, y = sumMoney }; int N, M; vector<Edge> edges; // Global variables to store the best solution found so far long long minV = -1; Point bestPoint; // We store the coefficients (A, B) that produced the best solution // so we can reconstruct the tree at the end for printing. long long bestA = 0, bestB = 0; // Union-Find (DSU) structures vector<int> parent; void dsu_init(int n) { parent.resize(n); for (int i = 0; i < n; ++i) parent[i] = i; } int dsu_find(int i) { if (parent[i] == i) return i; return parent[i] = dsu_find(parent[i]); } void dsu_union(int i, int j) { int root_i = dsu_find(i); int root_j = dsu_find(j); if (root_i != root_j) { parent[root_i] = root_j; } } // Kruskal's Algorithm with dynamic weights A*t + B*c // Returns the (SumTime, SumMoney) of the resulting tree Point getMST(long long A, long long B) { // Sort edges based on current weights sort(edges.begin(), edges.end(), [A, B](const Edge& a, const Edge& b) { long long valA = A * a.t + B * a.c; long long valB = A * b.t + B * b.c; return valA < valB; }); dsu_init(N); long long sumT = 0; long long sumC = 0; int edgesCount = 0; for (const auto& e : edges) { if (dsu_find(e.u) != dsu_find(e.v)) { dsu_union(e.u, e.v); sumT += e.t; sumC += e.c; edgesCount++; } } // Update global minimum if this tree is better long long currentV = sumT * sumC; if (minV == -1 || currentV < minV || (currentV == minV && sumT < bestPoint.x)) { minV = currentV; bestPoint = {sumT, sumC}; bestA = A; bestB = B; } return {sumT, sumC}; } // Recursive function to find hull points void solve(Point p1, Point p2) { // Calculate weights perpendicular to the line segment p1-p2 // We use absolute differences for positive weights long long A = abs(p1.y - p2.y); long long B = abs(p1.x - p2.x); // Run MST with new weights Point pNew = getMST(A, B); // Check if pNew is effectively the same as endpoints (prevents infinite loops) if (pNew.x == p1.x && pNew.y == p1.y) return; if (pNew.x == p2.x && pNew.y == p2.y) return; // Geometry check: Is pNew strictly "below" the segment p1-p2? // We check using cross product logic. // Vector P1->P2: (p2.x - p1.x, p2.y - p1.y) // Vector P1->New: (pNew.x - p1.x, pNew.y - p1.y) // Cross product (x1*y2 - x2*y1). If < 0, it's to the right (below/concave). long long cross_product = (p2.x - p1.x) * (pNew.y - p1.y) - (p2.y - p1.y) * (pNew.x - p1.x); // If cross_product >= 0, the point is not improving the lower hull if (cross_product >= 0) return; // Recurse solve(p1, pNew); solve(pNew, p2); } int main() { // Optimize I/O operations ios_base::sync_with_stdio(false); cin.tie(NULL); if (fopen("timeismoney.in", "r")) { freopen("timeismoney.in", "r", stdin); freopen("timeismoney.out", "w", stdout); } cin >> N >> M; for (int i = 0; i < M; ++i) { int u, v, t, c; cin >> u >> v >> t >> c; edges.push_back({u, v, t, c, i}); } // Step 1: Find extreme points // Minimize only Time (Weight: 1*t + 0*c) Point pTime = getMST(1, 0); // Minimize only Money (Weight: 0*t + 1*c) Point pMoney = getMST(0, 1); // Step 2: Start recursive search between the extremes solve(pTime, pMoney); // Step 3: Output cout << bestPoint.x << " " << bestPoint.y << endl; // To print the actual edges, we re-run the MST one last time // using the cached best weights to reconstruct the specific tree. sort(edges.begin(), edges.end(), [](const Edge& a, const Edge& b) { long long valA = bestA * a.t + bestB * a.c; long long valB = bestA * b.t + bestB * b.c; return valA < valB; }); dsu_init(N); for (const auto& e : edges) { if (dsu_find(e.u) != dsu_find(e.v)) { dsu_union(e.u, e.v); cout << e.u << " " << e.v << endl; } } return 0; }

Compilation message (stderr)

timeismoney.cpp: In function 'int main()':
timeismoney.cpp:130:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  130 |         freopen("timeismoney.in", "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
timeismoney.cpp:131:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  131 |         freopen("timeismoney.out", "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...