diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index acddcbd..0d631da 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,17 @@ on: branches: [master] jobs: + cpp-static-analysis: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install cppcheck + run: sudo apt-get install -y cppcheck + + - name: Run C++ static analysis + run: src/cpp/test/static_analysis.sh + cpp: runs-on: ubuntu-latest steps: @@ -21,6 +32,52 @@ jobs: - name: Run C++ BinarySearch test run: src/cpp/test/Search/test_binary_search.sh + - name: Run C++ Knapsack test + run: src/cpp/test/DP/test_knapsack.sh + + - name: Run C++ Dijkstra test + run: src/cpp/test/Graph/test_dijkstra.sh + + - name: Run C++ Floyd test + run: src/cpp/test/Graph/Floyd/test_floyd.sh + + - name: Run C++ Prim test + run: src/cpp/test/Graph/test_prim.sh + + - name: Run C++ GCD test + run: src/cpp/test/Math/Calc/test_gcd.sh + + - name: Run C++ LCM test + run: src/cpp/test/Math/Calc/test_lcm.sh + + - name: Run C++ Primes test + run: src/cpp/test/Math/Calc/test_primes.sh + + - name: Run C++ Comb test + run: src/cpp/test/Math/Combination/test_comb.sh + + - name: Run C++ ModPow test + run: src/cpp/test/Math/ModPow/test_modpow.sh + + - name: Run C++ SegmentTree test + run: src/cpp/test/Tree/SegmentTree/test_segmenttree.sh + + - name: Run C++ UnionFind test + run: src/cpp/test/Tree/UnionFind/test_unionfind.sh + + java-static-analysis: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '21' + + - name: Run Java static analysis + run: src/java/test/static_analysis.sh + java: runs-on: ubuntu-latest steps: @@ -39,3 +96,36 @@ jobs: - name: Run Java BinarySearch test run: src/java/test/Search/test_binary_search.sh + + - name: Run Java Knapsack test + run: src/java/test/DP/test_knapsack.sh + + - name: Run Java Dijkstra test + run: src/java/test/Graph/test_dijkstra.sh + + - name: Run Java Floyd test + run: src/java/test/Graph/Floyd/test_floyd.sh + + - name: Run Java Prim test + run: src/java/test/Graph/test_prim.sh + + - name: Run Java GCD test + run: src/java/test/Math/Calc/test_gcd.sh + + - name: Run Java LCM test + run: src/java/test/Math/Calc/test_lcm.sh + + - name: Run Java Primes test + run: src/java/test/Math/Calc/test_primes.sh + + - name: Run Java Comb test + run: src/java/test/Math/Combination/test_comb.sh + + - name: Run Java ModPow test + run: src/java/test/Math/ModPow/test_modpow.sh + + - name: Run Java SegTree test + run: src/java/test/Tree/SegmentTree/test_segtree.sh + + - name: Run Java UnionFind test + run: src/java/test/Tree/UnionFind/test_unionfind.sh diff --git a/README.md b/README.md index 6dd944e..2afd6b4 100644 --- a/README.md +++ b/README.md @@ -1 +1,32 @@ -

Implementation of algorithms

\ No newline at end of file +

Implementation of algorithms

+ +C++ and Java implementations. + +#### Algorithms + +| Category | Algorithm | Description | +|----------|-----------|-------------| +| DP | Knapsack | 0-1 knapsack problem | +| Graph | Dijkstra | Shortest path (non-negative edges) | +| Graph | Floyd | All-pairs shortest path, negative cycle detection | +| Graph | Prim | Minimum spanning tree | +| Math | GCD | Greatest common divisor | +| Math | LCM | Least common multiple | +| Math | Primes | Prime factorization, Sieve of Eratosthenes, Sieve of Atkin | +| Math | Combination | nCk with modular inverse | +| Math | ModPow | Modular exponentiation by repeated squaring | +| Search | BFS | Breadth-first search | +| Search | DFS | Depth-first search | +| Search | BinarySearch | Lower bound / upper bound | +| Tree | SegmentTree | Range Minimum Query | +| Tree | UnionFind | Union-Find with path compression | + +#### Test + +``` +# C++ +src/cpp/test//test_.sh + +# Java +src/java/test//test_.sh +``` diff --git a/src/cpp/lib/DP/Knapsack.cpp b/src/cpp/lib/DP/Knapsack.cpp index 4d8ca9b..f7d0a8c 100644 --- a/src/cpp/lib/DP/Knapsack.cpp +++ b/src/cpp/lib/DP/Knapsack.cpp @@ -1,15 +1,11 @@ #include using namespace std; -int main() { - int n, w; - cin >> n >> w; - - vector> arr(n); - for (int i = 0; i < n; i++) { - cin >> arr[i][0] >> arr[i][1]; - } - +// 0-1 Knapsack problem +// arr[i] = {value, weight} +// dp[i][j] = max value using first i items with capacity j +vector> knapsack(const vector>& arr, int w) { + int n = arr.size(); vector> dp(n + 1, vector(w + 1, 0)); for (int i = 1; i <= n; i++) { @@ -21,15 +17,5 @@ int main() { } } - cout << "DP table:" << endl; - for (int i = 0; i <= n; i++) { - for (int j = 0; j < w; j++) { - cout << dp[i][j] << " "; - } - cout << dp[i][w] << endl; - } - cout << "ans:" << endl; - cout << dp[n][w]; - - return 0; + return dp; } diff --git a/src/cpp/lib/Graph/Dijkstra.cpp b/src/cpp/lib/Graph/Dijkstra.cpp index 442b4f2..4306be3 100644 --- a/src/cpp/lib/Graph/Dijkstra.cpp +++ b/src/cpp/lib/Graph/Dijkstra.cpp @@ -1,4 +1,4 @@ -//コストが負の辺がない場合(最短から求めるため負の辺を後から取り込むことができない) +// For graphs with non-negative edge costs #include using namespace std; @@ -9,28 +9,14 @@ struct Node { } }; -int main() { - int n; - cin >> n; - - vector> adj(n); +vector dijkstra(int start, const vector>& adj) { + int n = adj.size(); vector d(n, INT_MAX); vector visit(n, false); - for (int i = 0; i < n; i++) { - int v, k; - cin >> v >> k; - for (int j = 0; j < k; j++) { - int u, c; - cin >> u >> c; - adj[v].push_back({u, c}); - } - } - - // dijkstra - d[0] = 0; + d[start] = 0; priority_queue, greater> pq; - pq.push({0, 0}); + pq.push({start, 0}); while (!pq.empty()) { Node nd = pq.top(); @@ -39,7 +25,7 @@ int main() { visit[v] = true; if (d[v] < nd.cost) continue; - for (auto& node : adj[v]) { + for (const auto& node : adj[v]) { int t = node.node; if (visit[t]) continue; if (d[t] > d[v] + node.cost) { @@ -49,9 +35,5 @@ int main() { } } - for (int i = 0; i < n; i++) { - cout << d[i] << " "; - } - - return 0; + return d; } diff --git a/src/cpp/lib/Graph/Floyd/Floyd.cpp b/src/cpp/lib/Graph/Floyd/Floyd.cpp index 5d54b6a..a49ac1a 100644 --- a/src/cpp/lib/Graph/Floyd/Floyd.cpp +++ b/src/cpp/lib/Graph/Floyd/Floyd.cpp @@ -1,21 +1,11 @@ #include using namespace std; -int main() { - int n, m; - cin >> n >> m; - - vector> edge(n, vector(n, INT_MAX)); - for (int i = 0; i < n; i++) edge[i][i] = 0; - - for (int i = 0; i < m; i++) { - int v, u, d; - cin >> v >> u >> d; - edge[v][u] = d; - } - - // floyd 計算量はノード数Vとした時、O(|V|^3)。 - for (int k = 0; k < n; k++) { // ノードiからjへ移動する時の経由地をkとする。 +// Floyd-Warshall. O(|V|^3). +// Returns true if a negative cycle is detected +bool floyd(vector>& edge) { + int n = edge.size(); + for (int k = 0; k < n; k++) { // k is the intermediate node from i to j for (int i = 0; i < n; i++) { if (edge[i][k] == INT_MAX) continue; for (int j = 0; j < n; j++) { @@ -25,21 +15,8 @@ int main() { } } - bool negative = false; for (int i = 0; i < n; i++) { - if (edge[i][i] < 0) negative = true; // 負の閉路があれば対自ノードへのコストは負となる。 - } - - if (negative) { - cout << "negative cycle" << endl; - } else { - for (int i = 0; i < n; i++) { - for (int j = 0; j < n - 1; j++) { - cout << edge[i][j] << " "; - } - cout << edge[i][n - 1] << endl; - } + if (edge[i][i] < 0) return true; // negative cycle: self-loop cost becomes negative } - - return 0; + return false; } diff --git a/src/cpp/lib/Graph/Prim.cpp b/src/cpp/lib/Graph/Prim.cpp index 837a3cb..8b6a53e 100644 --- a/src/cpp/lib/Graph/Prim.cpp +++ b/src/cpp/lib/Graph/Prim.cpp @@ -1,24 +1,13 @@ #include using namespace std; -int main() { - int n; - cin >> n; - - vector> edge(n, vector(n)); - vector d(n, INT_MAX); // 最小全域木を構成する時の始点からの距離 - vector p(n, -1); // 最小全域木を構成する時の親ノード +// Minimum spanning tree weight using Prim's algorithm +int prim(const vector>& edge) { + int n = edge.size(); + vector d(n, INT_MAX); // distance from start when constructing MST + vector p(n, -1); // parent node when constructing MST vector visited(n, false); - for (int i = 0; i < n; i++) { - for (int j = 0; j < n; j++) { - int t; - cin >> t; - edge[i][j] = (t == -1) ? INT_MAX : t; - } - } - - // prim d[0] = 0; while (true) { int minV = INT_MAX; @@ -47,7 +36,5 @@ int main() { sum += edge[i][p[i]]; } } - cout << sum << endl; - - return 0; + return sum; } diff --git a/src/cpp/lib/Math/Calc/GCD.cpp b/src/cpp/lib/Math/Calc/GCD.cpp new file mode 100644 index 0000000..ddf1ece --- /dev/null +++ b/src/cpp/lib/Math/Calc/GCD.cpp @@ -0,0 +1,8 @@ +#include +using namespace std; + +long long gcd(long long c, long long d) { + if (c < d) return gcd(d, c); + if (d == 0) return c; + return gcd(d, c % d); +} diff --git a/src/cpp/lib/Math/Calc/Primes.cpp b/src/cpp/lib/Math/Calc/Primes.cpp index 78f1fa7..d302a44 100644 --- a/src/cpp/lib/Math/Calc/Primes.cpp +++ b/src/cpp/lib/Math/Calc/Primes.cpp @@ -1,7 +1,7 @@ #include using namespace std; -// 素因数分解 +// Prime factorization // key: prime, value: count map primes(int n) { vector list; @@ -30,7 +30,7 @@ map primes(int n) { return mp; } -// n以下の素数列挙 +// List primes up to n // O(NloglogN) vector eratosthenes(int n) { vector flag(n + 1, false); @@ -51,7 +51,7 @@ vector eratosthenes(int n) { return list; } -// n以下の素数列挙 +// List primes up to n vector atkin(int n) { vector flag(n + 1, false); int sq = (int)sqrt(n); diff --git a/src/cpp/lib/Math/Combination/Comb.cpp b/src/cpp/lib/Math/Combination/Comb.cpp index 4ce9cb6..21e76d2 100644 --- a/src/cpp/lib/Math/Combination/Comb.cpp +++ b/src/cpp/lib/Math/Combination/Comb.cpp @@ -21,7 +21,7 @@ struct Comb { return b % 2 == 0 ? x * x % MOD : x * (x * a % MOD) % MOD; } - // 逆元。x^(-1)≡x^(p-2) (MOD p) xとpは互いに素。 + // Modular inverse. x^(-1) ≡ x^(p-2) (MOD p), x and p are coprime. long long inv(long long n) { return modpow(n, MOD - 2); } diff --git a/src/cpp/lib/Math/ModPow/ModPow.cpp b/src/cpp/lib/Math/ModPow/ModPow.cpp index e72b51c..5bda106 100644 --- a/src/cpp/lib/Math/ModPow/ModPow.cpp +++ b/src/cpp/lib/Math/ModPow/ModPow.cpp @@ -3,7 +3,7 @@ using namespace std; long long MOD; -// 繰り返し二乗法によるべき乗計算。O(logN)。 +// Modular exponentiation by repeated squaring. O(logN). long long power(long long x, long long n) { long long sum = 1; while (n > 0) { diff --git a/src/cpp/lib/Search/BFS/BFS.cpp b/src/cpp/lib/Search/BFS/BFS.cpp index a2f2163..3b98204 100644 --- a/src/cpp/lib/Search/BFS/BFS.cpp +++ b/src/cpp/lib/Search/BFS/BFS.cpp @@ -1,7 +1,7 @@ #include using namespace std; -void bfs(int s, vector>& adj, vector& d) { +void bfs(int s, const vector>& adj, vector& d) { fill(d.begin(), d.end(), INT_MAX); d[s] = 0; deque q; diff --git a/src/cpp/lib/Search/BinarySearch.cpp b/src/cpp/lib/Search/BinarySearch.cpp index ae93e5d..ef523bb 100644 --- a/src/cpp/lib/Search/BinarySearch.cpp +++ b/src/cpp/lib/Search/BinarySearch.cpp @@ -1,7 +1,7 @@ #include using namespace std; -int lowerBound(vector& arr, int value) { +int lowerBound(const vector& arr, int value) { int left = -1; int right = arr.size(); while (right - left > 1) { @@ -15,7 +15,7 @@ int lowerBound(vector& arr, int value) { return right; } -int upperBound(vector& arr, int value) { +int upperBound(const vector& arr, int value) { int left = -1; int right = arr.size(); while (right - left > 1) { diff --git a/src/cpp/lib/Tree/SegmentTree/SegTree.cpp b/src/cpp/lib/Tree/SegmentTree/SegmentTree.cpp similarity index 93% rename from src/cpp/lib/Tree/SegmentTree/SegTree.cpp rename to src/cpp/lib/Tree/SegmentTree/SegmentTree.cpp index f37f8e4..cab44e3 100644 --- a/src/cpp/lib/Tree/SegmentTree/SegTree.cpp +++ b/src/cpp/lib/Tree/SegmentTree/SegmentTree.cpp @@ -2,11 +2,11 @@ #include using namespace std; -struct SegTree { +struct SegmentTree { int n = 1; vector val; - SegTree(int n_) { + explicit SegmentTree(int n_) { while (n < n_) n *= 2; val.assign(2 * n - 1, INT_MAX); } diff --git a/src/cpp/lib/Tree/UnionFind/UnionFind.cpp b/src/cpp/lib/Tree/UnionFind/UnionFind.cpp index 06aa7e3..83a98d6 100644 --- a/src/cpp/lib/Tree/UnionFind/UnionFind.cpp +++ b/src/cpp/lib/Tree/UnionFind/UnionFind.cpp @@ -4,7 +4,7 @@ using namespace std; struct UnionFind { vector parent, rank_, size_; - UnionFind(int n) : parent(n), rank_(n, 0), size_(n, 1) { + explicit UnionFind(int n) : parent(n), rank_(n, 0), size_(n, 1) { for (int i = 0; i < n; i++) parent[i] = i; } @@ -13,7 +13,7 @@ struct UnionFind { return parent[x] = find(parent[x]); } - // 結合して木のサイズを更新 + // Unite and update tree size void unite1(int x, int y) { x = find(x); y = find(y); @@ -23,7 +23,7 @@ struct UnionFind { size_[x] += size_[y]; } - // 結合して木の深さを更新 + // Unite and update tree rank void unite2(int x, int y) { x = find(x); y = find(y); diff --git a/src/cpp/test/DP/test_knapsack.sh b/src/cpp/test/DP/test_knapsack.sh new file mode 100755 index 0000000..32de524 --- /dev/null +++ b/src/cpp/test/DP/test_knapsack.sh @@ -0,0 +1,89 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../lib/DP/Knapsack.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_knapsack" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int n, w; + cin >> n >> w; + vector> arr(n); + for (int i = 0; i < n; i++) { + cin >> arr[i][0] >> arr[i][1]; + } + vector> dp = knapsack(arr, w); + cout << "DP table:" << endl; + for (int i = 0; i <= n; i++) { + for (int j = 0; j < w; j++) { + cout << dp[i][j] << " "; + } + cout << dp[i][w] << endl; + } + cout << "ans:" << endl; + cout << dp[n][w]; + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: 3 items, capacity 4 +run_test "basic" \ +"3 4 +2 1 +3 2 +4 3" \ +"DP table: +0 0 0 0 0 +0 2 2 2 2 +0 2 3 5 5 +0 2 3 5 6 +ans: +6" + +# Test 2: no items fit +run_test "no fit" \ +"2 1 +5 2 +3 3" \ +"DP table: +0 0 +0 0 +0 0 +ans: +0" + +# Test 3: single item +run_test "single item" \ +"1 3 +5 2" \ +"DP table: +0 0 0 0 +0 0 5 5 +ans: +5" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Graph/Floyd/test_floyd.sh b/src/cpp/test/Graph/Floyd/test_floyd.sh new file mode 100755 index 0000000..6b5f5e9 --- /dev/null +++ b/src/cpp/test/Graph/Floyd/test_floyd.sh @@ -0,0 +1,84 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Graph/Floyd/Floyd.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_floyd" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int n, m; + cin >> n >> m; + vector> edge(n, vector(n, INT_MAX)); + for (int i = 0; i < n; i++) edge[i][i] = 0; + for (int i = 0; i < m; i++) { + int v, u, d; + cin >> v >> u >> d; + edge[v][u] = d; + } + bool negative = floyd(edge); + if (negative) { + cout << "negative cycle" << endl; + } else { + for (int i = 0; i < n; i++) { + for (int j = 0; j < n - 1; j++) { + cout << edge[i][j] << " "; + } + cout << edge[i][n - 1] << endl; + } + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: 3 nodes +run_test "3 nodes" \ +"3 4 +0 1 2 +0 2 5 +1 2 1 +2 0 7" \ +"0 2 3 +8 0 1 +7 9 0" + +# Test 2: 2 nodes bidirectional +run_test "2 nodes bidirectional" \ +"2 2 +0 1 3 +1 0 5" \ +"0 3 +5 0" + +# Test 3: negative cycle detection +run_test "negative cycle" \ +"3 3 +0 1 1 +1 2 -3 +2 0 1" \ +"negative cycle" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Graph/test_dijkstra.sh b/src/cpp/test/Graph/test_dijkstra.sh new file mode 100755 index 0000000..54d624e --- /dev/null +++ b/src/cpp/test/Graph/test_dijkstra.sh @@ -0,0 +1,76 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../lib/Graph/Dijkstra.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_dijkstra" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int n; + cin >> n; + vector> adj(n); + for (int i = 0; i < n; i++) { + int v, k; + cin >> v >> k; + for (int j = 0; j < k; j++) { + int u, c; + cin >> u >> c; + adj[v].push_back({u, c}); + } + } + vector d = dijkstra(0, adj); + for (int i = 0; i < n; i++) { + cout << d[i] << " "; + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: 4 nodes 0->1(1), 0->2(4), 1->2(2), 2->3(1) +run_test "basic graph" \ +"4 +0 2 1 1 2 4 +1 1 2 2 +2 1 3 1 +3 0" \ +"0 1 3 4 " + +# Test 2: 3 nodes linear 0->1(5), 1->2(3) +run_test "linear path" \ +"3 +0 1 1 5 +1 1 2 3 +2 0" \ +"0 5 8 " + +# Test 3: single node +run_test "single node" \ +"1 +0 0" \ +"0 " + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Graph/test_prim.sh b/src/cpp/test/Graph/test_prim.sh new file mode 100755 index 0000000..107afe3 --- /dev/null +++ b/src/cpp/test/Graph/test_prim.sh @@ -0,0 +1,72 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../lib/Graph/Prim.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_prim" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int n; + cin >> n; + vector> edge(n, vector(n)); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + int t; + cin >> t; + edge[i][j] = (t == -1) ? INT_MAX : t; + } + } + cout << prim(edge) << endl; + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: 3 nodes triangle +run_test "triangle" \ +"3 +-1 2 3 +2 -1 1 +3 1 -1" \ +"3" + +# Test 2: 4 nodes +run_test "4 nodes" \ +"4 +-1 2 -1 6 +2 -1 3 -1 +-1 3 -1 1 +6 -1 1 -1" \ +"6" + +# Test 3: 2 nodes +run_test "2 nodes" \ +"2 +-1 5 +5 -1" \ +"5" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Math/Calc/test_gcd.sh b/src/cpp/test/Math/Calc/test_gcd.sh new file mode 100755 index 0000000..fe94740 --- /dev/null +++ b/src/cpp/test/Math/Calc/test_gcd.sh @@ -0,0 +1,66 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/Calc/GCD.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_gcd" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int q; + cin >> q; + for (int i = 0; i < q; i++) { + long long c, d; + cin >> c >> d; + cout << gcd(c, d) << endl; + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: gcd(12,8)=4, gcd(7,13)=1, gcd(6,6)=6 +run_test "basic" \ +"3 +12 8 +7 13 +6 6" \ +"4 +1 +6" + +# Test 2: gcd(1,100)=1 +run_test "one is 1" \ +"1 +1 100" \ +"1" + +# Test 3: gcd(1000000,500000)=500000 +run_test "large values" \ +"1 +1000000 500000" \ +"500000" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Math/Calc/test_lcm.sh b/src/cpp/test/Math/Calc/test_lcm.sh new file mode 100755 index 0000000..89b9c0f --- /dev/null +++ b/src/cpp/test/Math/Calc/test_lcm.sh @@ -0,0 +1,66 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/Calc/LCM.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_lcm" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int q; + cin >> q; + for (int i = 0; i < q; i++) { + long long c, d; + cin >> c >> d; + cout << lcm(c, d) << endl; + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: lcm(12,8)=24, lcm(7,13)=91, lcm(6,6)=6 +run_test "basic" \ +"3 +12 8 +7 13 +6 6" \ +"24 +91 +6" + +# Test 2: lcm(1,100)=100 +run_test "one is 1" \ +"1 +1 100" \ +"100" + +# Test 3: lcm(1000000,500000)=1000000 +run_test "large values" \ +"1 +1000000 500000" \ +"1000000" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Math/Calc/test_primes.sh b/src/cpp/test/Math/Calc/test_primes.sh new file mode 100755 index 0000000..d2cd5de --- /dev/null +++ b/src/cpp/test/Math/Calc/test_primes.sh @@ -0,0 +1,86 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/Calc/Primes.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_primes" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + string cmd; + while (cin >> cmd) { + int n; + cin >> n; + if (cmd == "primes") { + map mp = primes(n); + bool first = true; + for (auto& p : mp) { + if (!first) cout << " "; + cout << p.first << "^" << p.second; + first = false; + } + cout << endl; + } else if (cmd == "eratosthenes") { + vector v = eratosthenes(n); + for (int i = 0; i < (int)v.size(); i++) { + if (i > 0) cout << " "; + cout << v[i]; + } + cout << endl; + } else if (cmd == "atkin") { + vector v = atkin(n); + for (int i = 0; i < (int)v.size(); i++) { + if (i > 0) cout << " "; + cout << v[i]; + } + cout << endl; + } + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: prime factorization 12=2^2*3 +run_test "prime factorization 12" \ +"primes 12" \ +"2^2 3^1" + +# Test 2: prime factorization 30=2*3*5 +run_test "prime factorization 30" \ +"primes 30" \ +"2^1 3^1 5^1" + +# Test 3: Sieve of Eratosthenes, primes up to 20 +run_test "eratosthenes 20" \ +"eratosthenes 20" \ +"2 3 5 7 11 13 17 19" + +# Test 4: Sieve of Atkin, primes up to 20 +run_test "atkin 20" \ +"atkin 20" \ +"2 3 5 7 11 13 17 19" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Math/Combination/test_comb.sh b/src/cpp/test/Math/Combination/test_comb.sh new file mode 100755 index 0000000..30238e9 --- /dev/null +++ b/src/cpp/test/Math/Combination/test_comb.sh @@ -0,0 +1,75 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/Combination/Comb.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_comb" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int n; + long long MOD; + cin >> n >> MOD; + Comb comb(n, MOD); + int q; + cin >> q; + for (int i = 0; i < q; i++) { + string cmd; + int a, b; + cin >> cmd >> a >> b; + if (cmd == "nCk1") { + cout << comb.nCk1(a, b) << endl; + } else if (cmd == "nCk2") { + cout << comb.nCk2(a, b) << endl; + } + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: basic nCk1 and nCk2 +run_test "basic combinations" \ +"10 1000000007 +4 +nCk1 5 2 +nCk1 10 3 +nCk2 5 2 +nCk1 3 5" \ +"10 +120 +10 +0" + +# Test 2: nCk(n,0)=1, nCk(n,n)=1 +run_test "edge cases" \ +"5 1000000007 +2 +nCk1 5 0 +nCk1 5 5" \ +"1 +1" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Math/ModPow/test_modpow.sh b/src/cpp/test/Math/ModPow/test_modpow.sh new file mode 100755 index 0000000..0f77035 --- /dev/null +++ b/src/cpp/test/Math/ModPow/test_modpow.sh @@ -0,0 +1,65 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/ModPow/ModPow.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_modpow" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int q; + cin >> q; + for (int i = 0; i < q; i++) { + long long x, n, m; + cin >> x >> n >> m; + MOD = m; + cout << power(x, n) << endl; + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: basic +run_test "basic powers" \ +"4 +2 10 1000000007 +3 5 1000000007 +2 29 1000000007 +10 9 7" \ +"1024 +243 +536870912 +6" + +# Test 2: exponent 0 and 1 +run_test "edge cases" \ +"2 +5 0 1000000007 +5 1 1000000007" \ +"1 +5" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Search/BFS/test_bfs.sh b/src/cpp/test/Search/BFS/test_bfs.sh index 10db456..6c37aa9 100755 --- a/src/cpp/test/Search/BFS/test_bfs.sh +++ b/src/cpp/test/Search/BFS/test_bfs.sh @@ -50,7 +50,7 @@ run_test() { fi } -# Test 1: 直線グラフ 1->2->3->4 +# Test 1: linear graph 1->2->3->4 run_test "linear graph" \ "4 1 1 2 @@ -62,7 +62,7 @@ run_test "linear graph" \ 3 dist: 2 4 dist: 3" -# Test 2: 星型グラフ 1->2, 1->3, 1->4 +# Test 2: star graph 1->2, 1->3, 1->4 run_test "star graph" \ "4 1 3 2 3 4 @@ -74,7 +74,7 @@ run_test "star graph" \ 3 dist: 1 4 dist: 1" -# Test 3: ダイヤモンド型 1->2, 1->3, 2->4, 3->4 +# Test 3: diamond graph 1->2, 1->3, 2->4, 3->4 run_test "diamond graph" \ "4 1 2 2 3 @@ -86,7 +86,7 @@ run_test "diamond graph" \ 3 dist: 1 4 dist: 2" -# Test 4: 単一ノード +# Test 4: single node run_test "single node" \ "1 1 0" \ diff --git a/src/cpp/test/Search/DFS/test_dfs.sh b/src/cpp/test/Search/DFS/test_dfs.sh index ec6311e..cc96e49 100755 --- a/src/cpp/test/Search/DFS/test_dfs.sh +++ b/src/cpp/test/Search/DFS/test_dfs.sh @@ -52,7 +52,7 @@ run_test() { fi } -# Test 1: 直線グラフ 1->2->3->4 +# Test 1: linear graph 1->2->3->4 run_test "linear graph" \ "4 1 1 2 @@ -64,7 +64,7 @@ run_test "linear graph" \ 3 3sec 6sec 4 4sec 5sec" -# Test 2: 星型グラフ 1->2, 1->3, 1->4 +# Test 2: star graph 1->2, 1->3, 1->4 run_test "star graph" \ "4 1 3 2 3 4 @@ -76,7 +76,7 @@ run_test "star graph" \ 3 4sec 5sec 4 6sec 7sec" -# Test 3: ダイヤモンド型 1->2, 1->3, 2->4, 3->4 +# Test 3: diamond graph 1->2, 1->3, 2->4, 3->4 run_test "diamond graph" \ "4 1 2 2 3 @@ -88,7 +88,7 @@ run_test "diamond graph" \ 3 6sec 7sec 4 3sec 4sec" -# Test 4: 単一ノード +# Test 4: single node run_test "single node" \ "1 1 0" \ diff --git a/src/cpp/test/Search/test_binary_search.sh b/src/cpp/test/Search/test_binary_search.sh index 41dafdf..9ab0fe2 100755 --- a/src/cpp/test/Search/test_binary_search.sh +++ b/src/cpp/test/Search/test_binary_search.sh @@ -42,7 +42,7 @@ run_test() { fi } -# Test 1: 基本ケース [1,2,3,4,5] で 3 を検索 +# Test 1: basic [1,2,3,4,5] search for 3 run_test "basic" \ "5 1 2 3 4 5 @@ -50,7 +50,7 @@ run_test "basic" \ 3" \ "lower:2 upper:3" -# Test 2: 重複あり [1,2,2,2,3] で 2 を検索 +# Test 2: duplicates [1,2,2,2,3] search for 2 run_test "duplicates" \ "5 1 2 2 2 3 @@ -58,7 +58,7 @@ run_test "duplicates" \ 2" \ "lower:1 upper:4" -# Test 3: 値が範囲外(大きい) [1,2,3] で 5 を検索 +# Test 3: out of range (too large) [1,2,3] search for 5 run_test "value too large" \ "3 1 2 3 @@ -66,7 +66,7 @@ run_test "value too large" \ 5" \ "lower:3 upper:3" -# Test 4: 値が範囲外(小さい) [2,3,4] で 1 を検索 +# Test 4: out of range (too small) [2,3,4] search for 1 run_test "value too small" \ "3 2 3 4 @@ -74,7 +74,7 @@ run_test "value too small" \ 1" \ "lower:0 upper:0" -# Test 5: 単一要素 [5] で 5 を検索 +# Test 5: single element [5] search for 5 run_test "single element" \ "1 5 diff --git a/src/cpp/test/Tree/SegmentTree/test_segmenttree.sh b/src/cpp/test/Tree/SegmentTree/test_segmenttree.sh new file mode 100755 index 0000000..54ef42c --- /dev/null +++ b/src/cpp/test/Tree/SegmentTree/test_segmenttree.sh @@ -0,0 +1,87 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Tree/SegmentTree/SegmentTree.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_segtree" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int n, q; + cin >> n >> q; + SegmentTree st(n); + for (int i = 0; i < q; i++) { + string cmd; + cin >> cmd; + if (cmd == "update") { + int k, a; + cin >> k >> a; + st.update(k, a); + } else if (cmd == "query") { + int a, b; + cin >> a >> b; + cout << st.query(a, b) << endl; + } + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: basic RMQ [5,3,7,1,4] +run_test "basic RMQ" \ +"5 7 +update 0 5 +update 1 3 +update 2 7 +update 3 1 +update 4 4 +query 0 5 +query 1 3" \ +"1 +3" + +# Test 2: update and re-query +run_test "update and re-query" \ +"3 6 +update 0 10 +update 1 20 +update 2 30 +query 0 3 +update 1 5 +query 0 3" \ +"10 +5" + +# Test 3: single element query +run_test "single element query" \ +"3 4 +update 0 3 +update 1 7 +update 2 5 +query 1 2" \ +"7" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/Tree/UnionFind/test_unionfind.sh b/src/cpp/test/Tree/UnionFind/test_unionfind.sh new file mode 100755 index 0000000..c1c7a42 --- /dev/null +++ b/src/cpp/test/Tree/UnionFind/test_unionfind.sh @@ -0,0 +1,88 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Tree/UnionFind/UnionFind.cpp" +TMPDIR=$(mktemp -d) +BIN="$TMPDIR/test_unionfind" + +cat "$SRC" > "$TMPDIR/test.cpp" +cat >> "$TMPDIR/test.cpp" << 'DRIVER' + +int main() { + int n, q; + cin >> n >> q; + UnionFind uf(n); + for (int i = 0; i < q; i++) { + string cmd; + cin >> cmd; + if (cmd == "unite") { + int x, y; + cin >> x >> y; + uf.unite1(x, y); + } else if (cmd == "same") { + int x, y; + cin >> x >> y; + cout << (uf.same(x, y) ? "yes" : "no") << endl; + } else if (cmd == "size") { + int x; + cin >> x; + cout << uf.size(x) << endl; + } + } + return 0; +} +DRIVER + +g++ -o "$BIN" "$TMPDIR/test.cpp" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | "$BIN") + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: basic union and find +run_test "basic union-find" \ +"5 9 +same 0 1 +unite 0 1 +same 0 1 +unite 2 3 +same 0 2 +unite 0 2 +same 0 3 +size 0 +size 4" \ +"no +yes +no +yes +4 +1" + +# Test 2: merge all nodes +run_test "merge all" \ +"3 5 +unite 0 1 +unite 1 2 +same 0 2 +size 0 +size 2" \ +"yes +3 +3" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/cpp/test/static_analysis.sh b/src/cpp/test/static_analysis.sh new file mode 100755 index 0000000..467981a --- /dev/null +++ b/src/cpp/test/static_analysis.sh @@ -0,0 +1,30 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +LIB_DIR="$SCRIPT_DIR/../lib" + +fail=0 +total=0 + +while IFS= read -r f; do + ((total++)) + name="${f#$LIB_DIR/}" + output=$(cppcheck \ + --enable=warning,style,performance,portability \ + --suppress=missingInclude \ + --suppress=unusedFunction \ + --std=c++17 \ + --error-exitcode=1 \ + --quiet \ + "$f" 2>&1) + if [ $? -ne 0 ]; then + echo "FAIL: $name" + echo "$output" + ((fail++)) + else + echo "PASS: $name" + fi +done < <(find "$LIB_DIR" -name "*.cpp" | sort) + +echo "" +echo "Result: $((total - fail))/$total passed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/lib/DP/Knapsack.java b/src/java/lib/DP/Knapsack.java index 5da4f72..bd3bc52 100644 --- a/src/java/lib/DP/Knapsack.java +++ b/src/java/lib/DP/Knapsack.java @@ -1,23 +1,12 @@ package DP; -import java.util.*; - public class Knapsack { - public static void main(String[] args) { - - Scanner sc = new Scanner(System.in); - - int n = sc.nextInt(); - int w = sc.nextInt(); - - int[][] arr = new int[n][2]; - - for (int i = 0; i < n; i++) { - arr[i][0] = sc.nextInt(); - arr[i][1] = sc.nextInt(); - } - + // 0-1 Knapsack problem + // arr[i] = {value, weight} + // dp[i][j] = max value using first i items with capacity j + public int[][] knapsack(int[][] arr, int w) { + int n = arr.length; int[][] dp = new int[n + 1][w + 1]; for (int i = 1; i <= n; i++) { @@ -29,14 +18,6 @@ public static void main(String[] args) { } } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i <= n; i++) { - for (int j = 0; j < w; j++) { - sb.append(dp[i][j] + " "); - } - sb.append(dp[i][w] + "\n"); - } - System.out.print("DP table:\n" + sb); - System.out.print("ans:\n" + dp[n][w]); + return dp; } } diff --git a/src/java/lib/Graph/Dijkstra.java b/src/java/lib/Graph/Dijkstra.java index 8ddb0e1..4edf231 100644 --- a/src/java/lib/Graph/Dijkstra.java +++ b/src/java/lib/Graph/Dijkstra.java @@ -1,4 +1,4 @@ -//コストが負の辺がない場合(最短から求めるため負の辺を後から取り込むことができない) +// For graphs with non-negative edge costs package Graph; @@ -6,78 +6,34 @@ public class Dijkstra { - Scanner sc = new Scanner(System.in); - int n = sc.nextInt(); - List[] adj = new ArrayList[n]; - PriorityQueue pq = new PriorityQueue<>(); - boolean[] visit = new boolean[n]; - int[] d = new int[n]; + public int[] dijkstra(int start, List[] adj) { + int n = adj.length; + int[] d = new int[n]; + boolean[] visit = new boolean[n]; + Arrays.fill(d, Integer.MAX_VALUE); - public static void main(String[] args){ - new Dijkstra().run(); - } - - void run() { - for (int i=0; i(); - for (int i=0; i pq, List[] adj, boolean[] visit) { - d[0] = 0; - pq.add(new Node(0, 0)); + d[start] = 0; + PriorityQueue pq = new PriorityQueue<>((a, b) -> a[1] - b[1]); + pq.add(new int[]{start, 0}); while (!pq.isEmpty()) { - Node nd = pq.poll(); - int v= nd.node; + int[] nd = pq.poll(); + int v = nd[0]; visit[v] = true; - if (d[v] d[v]+node.cost) { - d[t] = d[v]+node.cost; - pq.add(new Node(t, d[t])); + if (d[t] > d[v] + node[1]) { + d[t] = d[v] + node[1]; + pq.add(new int[]{t, d[t]}); } - } } - } - - class Node implements Comparable { - int node; - int cost; - public Node(int n, int c) { - this.node = n; - this.cost = c; - } - public int compareTo(Node nd) { - if (this.costnd.cost) return 1; - return 0; - } + return d; } } diff --git a/src/java/lib/Graph/Floyd/Floyd.java b/src/java/lib/Graph/Floyd/Floyd.java index c4ace42..bdeb98f 100644 --- a/src/java/lib/Graph/Floyd/Floyd.java +++ b/src/java/lib/Graph/Floyd/Floyd.java @@ -1,51 +1,23 @@ package Graph.Floyd; -import java.util.Scanner; +public class Floyd { -public class Floyd{ - static Scanner sc = new Scanner(System.in); - static int n = sc.nextInt(); - static int m = sc.nextInt(); - static int[][] edge = new int[n][n]; - - public static void main(String[] args){ - for (int i=0; id[i] && !visited[i]){ + for (int i = 0; i < n; i++) { + if (minV > d[i] && !visited[i]) { u = i; minV = d[i]; } } - if (u==-1) break; + if (u == -1) break; visited[u] = true; - for (int v=0; vedge[u][v]){ + for (int v = 0; v < n; v++) { + if (!visited[v] && edge[u][v] != Integer.MAX_VALUE) { + if (d[v] > edge[u][v]) { d[v] = edge[u][v]; p[v] = u; } @@ -48,11 +35,11 @@ public static void prim(){ } } int sum = 0; - for (int i=0; i primes(int n) { } /** - * n以下の素数列挙 + * List primes up to n * O(NloglogN) * @param n * @return @@ -70,7 +70,7 @@ List eratosthenes(int n) { } /** - * n以下の素数列挙 + * List primes up to n * @param n * @return */ diff --git a/src/java/lib/Math/Combination/Comb.java b/src/java/lib/Math/Combination/Comb.java index aa3acc4..1cf7cfb 100644 --- a/src/java/lib/Math/Combination/Comb.java +++ b/src/java/lib/Math/Combination/Comb.java @@ -1,7 +1,7 @@ package Math.Combination; public class Comb { - int n; // 要素数 + int n; // number of elements int MOD = (int)1e9+7; long[] facts; @@ -23,7 +23,7 @@ public long modpow(long a, long b){ return b%2 == 0 ? x * x % MOD : x * (x*a%MOD) % MOD; } - // 逆元。x^(-1)≡x^(p-2) (MOD p) xとpは互いに素。 + // Modular inverse. x^(-1) ≡ x^(p-2) (MOD p), x and p are coprime. public long inv(long n){ return modpow(n, MOD-2); } diff --git a/src/java/lib/Math/ModPow/ModPow.java b/src/java/lib/Math/ModPow/ModPow.java index 0b29b87..f494db2 100644 --- a/src/java/lib/Math/ModPow/ModPow.java +++ b/src/java/lib/Math/ModPow/ModPow.java @@ -2,7 +2,7 @@ public class ModPow { long MOD; - public long power(long x, long n){ // 繰り返し二乗法によるべき乗計算。O(logN)。 + public long power(long x, long n){ // Modular exponentiation by repeated squaring. O(logN). long sum = 1; while (n > 0){ if ((n & 1) == 1){ diff --git a/src/java/lib/Search/BFS/BFS.java b/src/java/lib/Search/BFS/BFS.java index ba29c60..f0edefc 100644 --- a/src/java/lib/Search/BFS/BFS.java +++ b/src/java/lib/Search/BFS/BFS.java @@ -1,10 +1,10 @@ -package Search.Bfs; +package Search.BFS; import java.util.List; import java.util.ArrayList; import java.util.ArrayDeque; -public class Bfs { +public class BFS { public int[] bfs(int s, List[] adj, int n) { int[] d = new int[n]; diff --git a/src/java/lib/Search/DFS/DFS.java b/src/java/lib/Search/DFS/DFS.java index d29ab6f..d515013 100644 --- a/src/java/lib/Search/DFS/DFS.java +++ b/src/java/lib/Search/DFS/DFS.java @@ -1,8 +1,8 @@ -package Search.Dfs; +package Search.DFS; import java.util.List; -public class Dfs { +public class DFS { private int sec = 0; diff --git a/src/java/lib/Tree/UnionFind/UnionFind.java b/src/java/lib/Tree/UnionFind/UnionFind.java index 54cc2c5..558d1bb 100644 --- a/src/java/lib/Tree/UnionFind/UnionFind.java +++ b/src/java/lib/Tree/UnionFind/UnionFind.java @@ -25,7 +25,7 @@ public int find(int x) { return parent[x] = find(parent[x]); } -// 結合して木のサイズを更新 +// Unite and update tree size public void unite1(int x, int y) { x = find(x); y = find(y); @@ -39,7 +39,7 @@ public void unite1(int x, int y) { size[x] += size[y]; } -// 結合して木の深さを更新 +// Unite and update tree rank public void unite2(int x, int y) { x = find(x); y = find(y); diff --git a/src/java/test/DP/test_knapsack.sh b/src/java/test/DP/test_knapsack.sh new file mode 100755 index 0000000..9e1c4d7 --- /dev/null +++ b/src/java/test/DP/test_knapsack.sh @@ -0,0 +1,98 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../lib/DP/Knapsack.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/DP" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/Knapsack.java" + +cat > "$PKG_DIR/KnapsackTest.java" << 'DRIVER' +package DP; +import java.util.Scanner; + +public class KnapsackTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int w = sc.nextInt(); + int[][] arr = new int[n][2]; + for (int i = 0; i < n; i++) { + arr[i][0] = sc.nextInt(); + arr[i][1] = sc.nextInt(); + } + Knapsack ks = new Knapsack(); + int[][] dp = ks.knapsack(arr, w); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i <= n; i++) { + for (int j = 0; j < w; j++) { + sb.append(dp[i][j] + " "); + } + sb.append(dp[i][w] + "\n"); + } + System.out.print("DP table:\n" + sb); + System.out.print("ans:\n" + dp[n][w]); + } +} +DRIVER + +javac "$PKG_DIR/Knapsack.java" "$PKG_DIR/KnapsackTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" DP.KnapsackTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: 3 items, capacity 4 +run_test "basic" \ +"3 4 +2 1 +3 2 +4 3" \ +"DP table: +0 0 0 0 0 +0 2 2 2 2 +0 2 3 5 5 +0 2 3 5 6 +ans: +6" + +# Test 2: no items fit +run_test "no fit" \ +"2 1 +5 2 +3 3" \ +"DP table: +0 0 +0 0 +0 0 +ans: +0" + +# Test 3: single item +run_test "single item" \ +"1 3 +5 2" \ +"DP table: +0 0 0 0 +0 0 5 5 +ans: +5" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Graph/Floyd/test_floyd.sh b/src/java/test/Graph/Floyd/test_floyd.sh new file mode 100755 index 0000000..1e53d22 --- /dev/null +++ b/src/java/test/Graph/Floyd/test_floyd.sh @@ -0,0 +1,97 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Graph/Floyd/Floyd.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Graph/Floyd" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/Floyd.java" + +cat > "$PKG_DIR/FloydTest.java" << 'DRIVER' +package Graph.Floyd; +import java.util.Scanner; + +public class FloydTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int m = sc.nextInt(); + int[][] edge = new int[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + edge[i][j] = (i == j) ? 0 : Integer.MAX_VALUE; + } + } + for (int i = 0; i < m; i++) { + int v = sc.nextInt(); + int u = sc.nextInt(); + int d = sc.nextInt(); + edge[v][u] = d; + } + Floyd f = new Floyd(); + boolean negative = f.floyd(edge); + if (negative) { + System.out.println("negative cycle"); + } else { + for (int i = 0; i < n; i++) { + for (int j = 0; j < n - 1; j++) { + System.out.print(edge[i][j] + " "); + } + System.out.println(edge[i][n - 1]); + } + } + } +} +DRIVER + +javac "$PKG_DIR/Floyd.java" "$PKG_DIR/FloydTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Graph.Floyd.FloydTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: 3 nodes +run_test "3 nodes" \ +"3 4 +0 1 2 +0 2 5 +1 2 1 +2 0 7" \ +"0 2 3 +8 0 1 +7 9 0" + +# Test 2: 2 nodes bidirectional +run_test "2 nodes bidirectional" \ +"2 2 +0 1 3 +1 0 5" \ +"0 3 +5 0" + +# Test 3: negative cycle detection +run_test "negative cycle" \ +"3 3 +0 1 1 +1 2 -3 +2 0 1" \ +"negative cycle" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Graph/test_dijkstra.sh b/src/java/test/Graph/test_dijkstra.sh new file mode 100755 index 0000000..161b58e --- /dev/null +++ b/src/java/test/Graph/test_dijkstra.sh @@ -0,0 +1,87 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../lib/Graph/Dijkstra.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Graph" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/Dijkstra.java" + +cat > "$PKG_DIR/DijkstraTest.java" << 'DRIVER' +package Graph; +import java.util.*; + +public class DijkstraTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + @SuppressWarnings("unchecked") + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (int i = 0; i < n; i++) { + int v = sc.nextInt(); + int k = sc.nextInt(); + for (int j = 0; j < k; j++) { + int u = sc.nextInt(); + int c = sc.nextInt(); + adj[v].add(new int[]{u, c}); + } + } + Dijkstra dij = new Dijkstra(); + int[] d = dij.dijkstra(0, adj); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + sb.append(d[i] + " "); + } + System.out.print(sb.toString()); + } +} +DRIVER + +javac "$PKG_DIR/Dijkstra.java" "$PKG_DIR/DijkstraTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Graph.DijkstraTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: 4 nodes 0->1(1), 0->2(4), 1->2(2), 2->3(1) +run_test "basic graph" \ +"4 +0 2 1 1 2 4 +1 1 2 2 +2 1 3 1 +3 0" \ +"0 1 3 4" + +# Test 2: 3 nodes linear 0->1(5), 1->2(3) +run_test "linear path" \ +"3 +0 1 1 5 +1 1 2 3 +2 0" \ +"0 5 8" + +# Test 3: single node +run_test "single node" \ +"1 +0 0" \ +"0" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Graph/test_prim.sh b/src/java/test/Graph/test_prim.sh new file mode 100755 index 0000000..53dfa99 --- /dev/null +++ b/src/java/test/Graph/test_prim.sh @@ -0,0 +1,78 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../lib/Graph/Prim.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Graph" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/Prim.java" + +cat > "$PKG_DIR/PrimTest.java" << 'DRIVER' +package Graph; +import java.util.Scanner; + +public class PrimTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int[][] edge = new int[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + int t = sc.nextInt(); + edge[i][j] = t == -1 ? Integer.MAX_VALUE : t; + } + } + Prim p = new Prim(); + System.out.println(p.prim(edge)); + } +} +DRIVER + +javac "$PKG_DIR/Prim.java" "$PKG_DIR/PrimTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Graph.PrimTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: 3 nodes triangle +run_test "triangle" \ +"3 +-1 2 3 +2 -1 1 +3 1 -1" \ +"3" + +# Test 2: 4 nodes +run_test "4 nodes" \ +"4 +-1 2 -1 6 +2 -1 3 -1 +-1 3 -1 1 +6 -1 1 -1" \ +"6" + +# Test 3: 2 nodes +run_test "2 nodes" \ +"2 +-1 5 +5 -1" \ +"5" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Math/Calc/test_gcd.sh b/src/java/test/Math/Calc/test_gcd.sh new file mode 100755 index 0000000..20164ae --- /dev/null +++ b/src/java/test/Math/Calc/test_gcd.sh @@ -0,0 +1,73 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/Calc/GCD.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Math/Calc" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/GCD.java" + +cat > "$PKG_DIR/GCDTest.java" << 'DRIVER' +package Math.Calc; +import java.util.Scanner; + +public class GCDTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int q = sc.nextInt(); + GCD g = new GCD(); + for (int i = 0; i < q; i++) { + long c = sc.nextLong(); + long d = sc.nextLong(); + System.out.println(g.gcd(c, d)); + } + } +} +DRIVER + +javac "$PKG_DIR/GCD.java" "$PKG_DIR/GCDTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Math.Calc.GCDTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: gcd(12,8)=4, gcd(7,13)=1, gcd(6,6)=6 +run_test "basic" \ +"3 +12 8 +7 13 +6 6" \ +"4 +1 +6" + +# Test 2: gcd(1,100)=1 +run_test "one is 1" \ +"1 +1 100" \ +"1" + +# Test 3: gcd(1000000,500000)=500000 +run_test "large values" \ +"1 +1000000 500000" \ +"500000" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Math/Calc/test_lcm.sh b/src/java/test/Math/Calc/test_lcm.sh new file mode 100755 index 0000000..51e998c --- /dev/null +++ b/src/java/test/Math/Calc/test_lcm.sh @@ -0,0 +1,73 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/Calc/LCM.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Math/Calc" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/LCM.java" + +cat > "$PKG_DIR/LCMTest.java" << 'DRIVER' +package Math.Calc; +import java.util.Scanner; + +public class LCMTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int q = sc.nextInt(); + LCM l = new LCM(); + for (int i = 0; i < q; i++) { + long c = sc.nextLong(); + long d = sc.nextLong(); + System.out.println(l.lcm(c, d)); + } + } +} +DRIVER + +javac "$PKG_DIR/LCM.java" "$PKG_DIR/LCMTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Math.Calc.LCMTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: lcm(12,8)=24, lcm(7,13)=91, lcm(6,6)=6 +run_test "basic" \ +"3 +12 8 +7 13 +6 6" \ +"24 +91 +6" + +# Test 2: lcm(1,100)=100 +run_test "one is 1" \ +"1 +1 100" \ +"100" + +# Test 3: lcm(1000000,500000)=1000000 +run_test "large values" \ +"1 +1000000 500000" \ +"1000000" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Math/Calc/test_primes.sh b/src/java/test/Math/Calc/test_primes.sh new file mode 100755 index 0000000..ee7fe87 --- /dev/null +++ b/src/java/test/Math/Calc/test_primes.sh @@ -0,0 +1,97 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/Calc/Primes.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Math/Calc" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/Primes.java" + +cat > "$PKG_DIR/PrimesTest.java" << 'DRIVER' +package Math.Calc; +import java.util.*; + +public class PrimesTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + Primes p = new Primes(); + while (sc.hasNext()) { + String cmd = sc.next(); + int n = sc.nextInt(); + if (cmd.equals("primes")) { + Map mp = p.primes(n); + TreeMap sorted = new TreeMap<>(mp); + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (Map.Entry e : sorted.entrySet()) { + if (!first) sb.append(" "); + sb.append(e.getKey() + "^" + e.getValue()); + first = false; + } + System.out.println(sb.toString()); + } else if (cmd.equals("eratosthenes")) { + List list = p.eratosthenes(n); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < list.size(); i++) { + if (i > 0) sb.append(" "); + sb.append(list.get(i)); + } + System.out.println(sb.toString()); + } else if (cmd.equals("atkin")) { + List list = p.atkin(n); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < list.size(); i++) { + if (i > 0) sb.append(" "); + sb.append(list.get(i)); + } + System.out.println(sb.toString()); + } + } + } +} +DRIVER + +javac "$PKG_DIR/Primes.java" "$PKG_DIR/PrimesTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Math.Calc.PrimesTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: prime factorization 12=2^2*3 +run_test "prime factorization 12" \ +"primes 12" \ +"2^2 3^1" + +# Test 2: prime factorization 30=2*3*5 +run_test "prime factorization 30" \ +"primes 30" \ +"2^1 3^1 5^1" + +# Test 3: Sieve of Eratosthenes, primes up to 20 +run_test "eratosthenes 20" \ +"eratosthenes 20" \ +"2 3 5 7 11 13 17 19" + +# Test 4: Sieve of Atkin, primes up to 20 +run_test "atkin 20" \ +"atkin 20" \ +"2 3 5 7 11 13 17 19" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Math/Combination/test_comb.sh b/src/java/test/Math/Combination/test_comb.sh new file mode 100755 index 0000000..37c9134 --- /dev/null +++ b/src/java/test/Math/Combination/test_comb.sh @@ -0,0 +1,80 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/Combination/Comb.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Math/Combination" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/Comb.java" + +cat > "$PKG_DIR/CombTest.java" << 'DRIVER' +package Math.Combination; +import java.util.Scanner; + +public class CombTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int MOD = sc.nextInt(); + Comb comb = new Comb(n, MOD); + int q = sc.nextInt(); + for (int i = 0; i < q; i++) { + String cmd = sc.next(); + int a = sc.nextInt(); + int b = sc.nextInt(); + if (cmd.equals("nCk1")) { + System.out.println(comb.nCk1(a, b)); + } else if (cmd.equals("nCk2")) { + System.out.println(comb.nCk2(a, b)); + } + } + } +} +DRIVER + +javac "$PKG_DIR/Comb.java" "$PKG_DIR/CombTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Math.Combination.CombTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: basic nCk1 and nCk2 +run_test "basic combinations" \ +"10 1000000007 +4 +nCk1 5 2 +nCk1 10 3 +nCk2 5 2 +nCk1 3 5" \ +"10 +120 +10 +0" + +# Test 2: nCk(n,0)=1, nCk(n,n)=1 +run_test "edge cases" \ +"5 1000000007 +2 +nCk1 5 0 +nCk1 5 5" \ +"1 +1" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Math/ModPow/test_modpow.sh b/src/java/test/Math/ModPow/test_modpow.sh new file mode 100755 index 0000000..6cdf0cd --- /dev/null +++ b/src/java/test/Math/ModPow/test_modpow.sh @@ -0,0 +1,73 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Math/ModPow/ModPow.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Math/ModPow" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/ModPow.java" + +cat > "$PKG_DIR/ModPowTest.java" << 'DRIVER' +package Math.ModPow; +import java.util.Scanner; + +public class ModPowTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int q = sc.nextInt(); + for (int i = 0; i < q; i++) { + long x = sc.nextLong(); + long n = sc.nextLong(); + long m = sc.nextLong(); + ModPow mp = new ModPow(); + mp.MOD = m; + System.out.println(mp.power(x, n)); + } + } +} +DRIVER + +javac "$PKG_DIR/ModPow.java" "$PKG_DIR/ModPowTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Math.ModPow.ModPowTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: basic +run_test "basic powers" \ +"4 +2 10 1000000007 +3 5 1000000007 +2 29 1000000007 +10 9 7" \ +"1024 +243 +536870912 +6" + +# Test 2: exponent 0 and 1 +run_test "edge cases" \ +"2 +5 0 1000000007 +5 1 1000000007" \ +"1 +5" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Search/BFS/test_bfs.sh b/src/java/test/Search/BFS/test_bfs.sh index 289a2a7..20522b7 100755 --- a/src/java/test/Search/BFS/test_bfs.sh +++ b/src/java/test/Search/BFS/test_bfs.sh @@ -2,17 +2,17 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SRC="$SCRIPT_DIR/../../../lib/Search/BFS/BFS.java" TMPDIR=$(mktemp -d) -PKG_DIR="$TMPDIR/Search/Bfs" +PKG_DIR="$TMPDIR/Search/BFS" mkdir -p "$PKG_DIR" -cp "$SRC" "$PKG_DIR/Bfs.java" +cp "$SRC" "$PKG_DIR/BFS.java" # Create test driver in the same package -cat > "$PKG_DIR/BfsTest.java" << 'DRIVER' -package Search.Bfs; +cat > "$PKG_DIR/BFSTest.java" << 'DRIVER' +package Search.BFS; import java.util.*; -public class BfsTest { +public class BFSTest { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); @@ -27,7 +27,7 @@ public class BfsTest { adj[t].add(u); } } - Bfs bfs = new Bfs(); + BFS bfs = new BFS(); int[] d = bfs.bfs(0, adj, n); for (int i = 0; i < n; i++) { System.out.println((i + 1) + " dist: " + d[i]); @@ -36,14 +36,14 @@ public class BfsTest { } DRIVER -javac "$PKG_DIR/Bfs.java" "$PKG_DIR/BfsTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } +javac "$PKG_DIR/BFS.java" "$PKG_DIR/BFSTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } pass=0 fail=0 run_test() { local name="$1" input="$2" expected="$3" - actual=$(echo "$input" | java -cp "$TMPDIR" Search.Bfs.BfsTest | sed 's/[[:space:]]*$//') + actual=$(echo "$input" | java -cp "$TMPDIR" Search.BFS.BFSTest | sed 's/[[:space:]]*$//') expected=$(echo "$expected" | sed 's/[[:space:]]*$//') if [ "$actual" = "$expected" ]; then echo "PASS: $name" @@ -56,7 +56,7 @@ run_test() { fi } -# Test 1: 直線グラフ 1->2->3->4 +# Test 1: linear graph 1->2->3->4 run_test "linear graph" \ "4 1 1 2 @@ -68,7 +68,7 @@ run_test "linear graph" \ 3 dist: 2 4 dist: 3" -# Test 2: 星型グラフ 1->2, 1->3, 1->4 +# Test 2: star graph 1->2, 1->3, 1->4 run_test "star graph" \ "4 1 3 2 3 4 @@ -80,7 +80,7 @@ run_test "star graph" \ 3 dist: 1 4 dist: 1" -# Test 3: ダイヤモンド型 1->2, 1->3, 2->4, 3->4 +# Test 3: diamond graph 1->2, 1->3, 2->4, 3->4 run_test "diamond graph" \ "4 1 2 2 3 @@ -92,7 +92,7 @@ run_test "diamond graph" \ 3 dist: 1 4 dist: 2" -# Test 4: 単一ノード +# Test 4: single node run_test "single node" \ "1 1 0" \ diff --git a/src/java/test/Search/DFS/test_dfs.sh b/src/java/test/Search/DFS/test_dfs.sh index c081aa8..4e84f26 100755 --- a/src/java/test/Search/DFS/test_dfs.sh +++ b/src/java/test/Search/DFS/test_dfs.sh @@ -2,17 +2,17 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SRC="$SCRIPT_DIR/../../../lib/Search/DFS/DFS.java" TMPDIR=$(mktemp -d) -PKG_DIR="$TMPDIR/Search/Dfs" +PKG_DIR="$TMPDIR/Search/DFS" mkdir -p "$PKG_DIR" -cp "$SRC" "$PKG_DIR/Dfs.java" +cp "$SRC" "$PKG_DIR/DFS.java" # Create test driver in the same package -cat > "$PKG_DIR/DfsTest.java" << 'DRIVER' -package Search.Dfs; +cat > "$PKG_DIR/DFSTest.java" << 'DRIVER' +package Search.DFS; import java.util.*; -public class DfsTest { +public class DFSTest { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); @@ -30,7 +30,7 @@ public class DfsTest { boolean[] visit = new boolean[n]; int[] firstV = new int[n]; int[] endV = new int[n]; - Dfs dfs = new Dfs(); + DFS dfs = new DFS(); dfs.dfs(0, edge, visit, firstV, endV); for (int i = 0; i < n; i++) { System.out.println((i + 1) + " " + firstV[i] + "sec " + endV[i] + "sec"); @@ -39,14 +39,14 @@ public class DfsTest { } DRIVER -javac "$PKG_DIR/Dfs.java" "$PKG_DIR/DfsTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } +javac "$PKG_DIR/DFS.java" "$PKG_DIR/DFSTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } pass=0 fail=0 run_test() { local name="$1" input="$2" expected="$3" - actual=$(echo "$input" | java -cp "$TMPDIR" Search.Dfs.DfsTest | sed 's/[[:space:]]*$//') + actual=$(echo "$input" | java -cp "$TMPDIR" Search.DFS.DFSTest | sed 's/[[:space:]]*$//') expected=$(echo "$expected" | sed 's/[[:space:]]*$//') if [ "$actual" = "$expected" ]; then echo "PASS: $name" @@ -59,7 +59,7 @@ run_test() { fi } -# Test 1: 直線グラフ 1->2->3->4 +# Test 1: linear graph 1->2->3->4 run_test "linear graph" \ "4 1 1 2 @@ -71,7 +71,7 @@ run_test "linear graph" \ 3 3sec 6sec 4 4sec 5sec" -# Test 2: 星型グラフ 1->2, 1->3, 1->4 +# Test 2: star graph 1->2, 1->3, 1->4 run_test "star graph" \ "4 1 3 2 3 4 @@ -83,7 +83,7 @@ run_test "star graph" \ 3 4sec 5sec 4 6sec 7sec" -# Test 3: ダイヤモンド型 1->2, 1->3, 2->4, 3->4 +# Test 3: diamond graph 1->2, 1->3, 2->4, 3->4 run_test "diamond graph" \ "4 1 2 2 3 @@ -95,7 +95,7 @@ run_test "diamond graph" \ 3 6sec 7sec 4 3sec 4sec" -# Test 4: 単一ノード +# Test 4: single node run_test "single node" \ "1 1 0" \ diff --git a/src/java/test/Search/test_binary_search.sh b/src/java/test/Search/test_binary_search.sh index 6609ec0..7e3ecab 100755 --- a/src/java/test/Search/test_binary_search.sh +++ b/src/java/test/Search/test_binary_search.sh @@ -48,7 +48,7 @@ run_test() { fi } -# Test 1: 基本ケース [1,2,3,4,5] で 3 を検索 +# Test 1: basic [1,2,3,4,5] search for 3 run_test "basic" \ "5 1 2 3 4 5 @@ -56,7 +56,7 @@ run_test "basic" \ 3" \ "lower:2 upper:3" -# Test 2: 重複あり [1,2,2,2,3] で 2 を検索 +# Test 2: duplicates [1,2,2,2,3] search for 2 run_test "duplicates" \ "5 1 2 2 2 3 @@ -64,7 +64,7 @@ run_test "duplicates" \ 2" \ "lower:1 upper:4" -# Test 3: 値が範囲外(大きい) [1,2,3] で 5 を検索 +# Test 3: out of range (too large) [1,2,3] search for 5 run_test "value too large" \ "3 1 2 3 @@ -72,7 +72,7 @@ run_test "value too large" \ 5" \ "lower:3 upper:3" -# Test 4: 値が範囲外(小さい) [2,3,4] で 1 を検索 +# Test 4: out of range (too small) [2,3,4] search for 1 run_test "value too small" \ "3 2 3 4 @@ -80,7 +80,7 @@ run_test "value too small" \ 1" \ "lower:0 upper:0" -# Test 5: 単一要素 [5] で 5 を検索 +# Test 5: single element [5] search for 5 run_test "single element" \ "1 5 diff --git a/src/java/test/Tree/SegmentTree/test_segtree.sh b/src/java/test/Tree/SegmentTree/test_segtree.sh new file mode 100755 index 0000000..9ae6790 --- /dev/null +++ b/src/java/test/Tree/SegmentTree/test_segtree.sh @@ -0,0 +1,94 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Tree/SegmentTree/SegTree.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Tree/SegmentTree" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/SegTree.java" + +cat > "$PKG_DIR/SegTreeTest.java" << 'DRIVER' +package Tree.SegmentTree; +import java.util.Scanner; + +public class SegTreeTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int q = sc.nextInt(); + SegTree st = new SegTree(n); + st.init(n); + for (int i = 0; i < q; i++) { + String cmd = sc.next(); + if (cmd.equals("update")) { + int k = sc.nextInt(); + int a = sc.nextInt(); + st.update(k, a); + } else if (cmd.equals("query")) { + int a = sc.nextInt(); + int b = sc.nextInt(); + System.out.println(st.query(a, b)); + } + } + } +} +DRIVER + +javac "$PKG_DIR/SegTree.java" "$PKG_DIR/SegTreeTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Tree.SegmentTree.SegTreeTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: basic RMQ [5,3,7,1,4] +run_test "basic RMQ" \ +"5 7 +update 0 5 +update 1 3 +update 2 7 +update 3 1 +update 4 4 +query 0 5 +query 1 3" \ +"1 +3" + +# Test 2: update and re-query +run_test "update and re-query" \ +"3 6 +update 0 10 +update 1 20 +update 2 30 +query 0 3 +update 1 5 +query 0 3" \ +"10 +5" + +# Test 3: single element query +run_test "single element query" \ +"3 4 +update 0 3 +update 1 7 +update 2 5 +query 1 2" \ +"7" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/Tree/UnionFind/test_unionfind.sh b/src/java/test/Tree/UnionFind/test_unionfind.sh new file mode 100755 index 0000000..a31ae0c --- /dev/null +++ b/src/java/test/Tree/UnionFind/test_unionfind.sh @@ -0,0 +1,93 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SRC="$SCRIPT_DIR/../../../lib/Tree/UnionFind/UnionFind.java" +TMPDIR=$(mktemp -d) +PKG_DIR="$TMPDIR/Tree/UnionFind" + +mkdir -p "$PKG_DIR" +cp "$SRC" "$PKG_DIR/UnionFind.java" + +cat > "$PKG_DIR/UnionFindTest.java" << 'DRIVER' +package Tree.UnionFind; +import java.util.Scanner; + +public class UnionFindTest { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int q = sc.nextInt(); + UnionFind uf = new UnionFind(n); + for (int i = 0; i < q; i++) { + String cmd = sc.next(); + if (cmd.equals("unite")) { + int x = sc.nextInt(); + int y = sc.nextInt(); + uf.unite1(x, y); + } else if (cmd.equals("same")) { + int x = sc.nextInt(); + int y = sc.nextInt(); + System.out.println(uf.same(x, y) ? "yes" : "no"); + } else if (cmd.equals("size")) { + int x = sc.nextInt(); + System.out.println(uf.size(x)); + } + } + } +} +DRIVER + +javac "$PKG_DIR/UnionFind.java" "$PKG_DIR/UnionFindTest.java" || { echo "COMPILE FAILED"; rm -rf "$TMPDIR"; exit 1; } + +pass=0 +fail=0 + +run_test() { + local name="$1" input="$2" expected="$3" + actual=$(echo "$input" | java -cp "$TMPDIR" Tree.UnionFind.UnionFindTest | sed 's/[[:space:]]*$//') + expected=$(echo "$expected" | sed 's/[[:space:]]*$//') + if [ "$actual" = "$expected" ]; then + echo "PASS: $name" + ((pass++)) + else + echo "FAIL: $name" + echo " expected: $expected" + echo " actual: $actual" + ((fail++)) + fi +} + +# Test 1: basic union and find +run_test "basic union-find" \ +"5 9 +same 0 1 +unite 0 1 +same 0 1 +unite 2 3 +same 0 2 +unite 0 2 +same 0 3 +size 0 +size 4" \ +"no +yes +no +yes +4 +1" + +# Test 2: merge all nodes +run_test "merge all" \ +"3 5 +unite 0 1 +unite 1 2 +same 0 2 +size 0 +size 2" \ +"yes +3 +3" + +rm -rf "$TMPDIR" +echo "" +echo "Result: $pass passed, $fail failed" +[ "$fail" -eq 0 ] && exit 0 || exit 1 diff --git a/src/java/test/static_analysis.sh b/src/java/test/static_analysis.sh new file mode 100755 index 0000000..e6fe6cf --- /dev/null +++ b/src/java/test/static_analysis.sh @@ -0,0 +1,19 @@ +#!/bin/bash +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +LIB_DIR="$SCRIPT_DIR/../lib" +TMPDIR=$(mktemp -d) + +files=$(find "$LIB_DIR" -name "*.java" | sort) +output=$(javac -Xlint:all -Werror -sourcepath "$LIB_DIR" -d "$TMPDIR" $files 2>&1) +status=$? + +if [ $status -ne 0 ]; then + echo "FAIL: static analysis found issues" + echo "$output" +else + count=$(echo "$files" | wc -l) + echo "PASS: all $count files passed static analysis" +fi + +rm -rf "$TMPDIR" +exit $status