You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CSES Grid Paths问题Java代码微优化技术咨询

Optimizations for CSES Grid Paths to Beat the 1-Second Threshold

Let's walk through targeted micro-optimizations to squeeze just enough performance out of your recursive backtracking solution. Your current code is already well-optimized with the key pruning rule, but these tweaks will cut down on overhead in the hot path (the recursive solve method) to get you under the time limit.

1. Replace 2D visited Array with a Bitmask

A 7×7 grid has exactly 49 cells—perfect for storing visited state in a single long (which has 64 bits). Bitwise operations are far faster than array index lookups, as they avoid double memory dereferences and are easier for the JVM to optimize.

  • Instead of boolean[][] visited, use a long mask where the (i*7 + j)-th bit represents whether cell (i,j) is visited.
  • To mark a cell as visited: mask |= 1L << (i*7 + j)
  • To check if a cell is unvisited: (mask & (1L << (pos))) == 0 (where pos = i*7 + j)

2. Inline the works Function

Function calls have small but cumulative overhead, especially in a tight recursive loop. Since works is a tiny function, inline its logic directly into the solve method to eliminate call stack overhead.

3. Use Direction Loops to Reduce Code Duplication

Your four direction checks are nearly identical. Using a loop over pre-defined direction deltas will reduce redundant code and help the JIT compiler optimize the hot path more effectively.

4. Simplify Pruning Condition Logic

The pruning check can be rewritten to avoid nested negations and redundant calculations. Precompute the positions you need to check for each direction to avoid recalculating indices multiple times.

5. Mark Static Variables as final (Where Possible)

Since board is initialized once and never modified, marking it static final gives the JVM more hints for optimization, as it knows the value won't change.


Modified Code with All Optimizations

import java.io.*;

public class GridPaths {
    public static class FastIO {
        InputStream dis;
        byte[] buffer = new byte[1 << 17];
        int pointer = 0;

        public FastIO(String fileName) throws Exception {
            dis = new FileInputStream(fileName);
        }

        public FastIO(InputStream is) {
            dis = is;
        }

        int nextInt() throws Exception {
            int ret = 0;
            byte b;
            do {
                b = nextByte();
            } while (b <= ' ');
            boolean negative = false;
            if (b == '-') {
                negative = true;
                b = nextByte();
            }
            while (b >= '0' && b <= '9') {
                ret = 10 * ret + b - '0';
                b = nextByte();
            }
            return negative ? -ret : ret;
        }

        long nextLong() throws Exception {
            long ret = 0;
            byte b;
            do {
                b = nextByte();
            } while (b <= ' ');
            boolean negative = false;
            if (b == '-') {
                negative = true;
                b = nextByte();
            }
            while (b >= '0' && b <= '9') {
                ret = 10 * ret + b - '0';
                b = nextByte();
            }
            return negative ? -ret : ret;
        }

        Integer[] readArray(int n) throws Exception {
            Integer[] a = new Integer[n];
            for (int i = 0; i < n; i++)
                a[i] = nextInt();
            return a;
        }

        byte nextByte() throws Exception {
            if (pointer == buffer.length) {
                dis.read(buffer, 0, buffer.length);
                pointer = 0;
            }
            return buffer[pointer++];
        }

        String next() throws Exception {
            StringBuilder ret = new StringBuilder();
            byte b;
            do {
                b = nextByte();
            } while (b <= ' ');
            while (b > ' ') {
                ret.appendCodePoint(b);
                b = nextByte();
            }
            return ret.toString();
        }
    }

    static final char[] board;
    static int ans = 0;
    // Direction deltas: left, right, up, down
    private static final int[][] DIRS = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
    private static final char[] DIR_CHARS = {'L', 'R', 'U', 'D'};

    static {
        try {
            FastIO in = new FastIO(System.in);
            board = in.next().toCharArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void solve(int i, int j, int steps, long mask) {
        // Early exit if we reach the end but haven't used all steps
        if (i == 6 && j == 0) {
            if (steps == 48) ans++;
            return;
        }
        // Early exit if we've used more steps than allowed (safe guard)
        if (steps >= 48) return;

        int pos = i * 7 + j;
        // Mark current cell as visited
        long newMask = mask | (1L << pos);

        for (int d = 0; d < 4; d++) {
            char dirChar = DIR_CHARS[d];
            // Skip if the current step doesn't allow this direction
            if (board[steps] != '?' && board[steps] != dirChar) continue;

            int ni = i + DIRS[d][0];
            int nj = j + DIRS[d][1];
            int nPos = ni * 7 + nj;

            // Check if new position is in bounds and unvisited
            if (ni < 0 || ni > 6 || nj < 0 || nj > 6) continue;
            if ((newMask & (1L << nPos)) != 0) continue;

            // Pruning check: avoid closing off a section of the grid
            boolean prune = false;
            if (d == 0) { // Left
                int farLeft = nj - 1;
                boolean farLeftBlocked = (farLeft < 0 || (mask & (1L << (i*7 + farLeft))) != 0);
                boolean downOpen = (ni + 1 <=6 && (mask & (1L << ((ni+1)*7 + nj))) == 0);
                boolean upOpen = (ni -1 >=0 && (mask & (1L << ((ni-1)*7 + nj))) ==0);
                prune = farLeftBlocked && downOpen && upOpen;
            } else if (d == 1) { // Right
                int farRight = nj +1;
                boolean farRightBlocked = (farRight >6 || (mask & (1L << (i*7 + farRight))) !=0);
                boolean downOpen = (ni +1 <=6 && (mask & (1L << ((ni+1)*7 + nj))) ==0);
                boolean upOpen = (ni -1 >=0 && (mask & (1L << ((ni-1)*7 + nj))) ==0);
                prune = farRightBlocked && downOpen && upOpen;
            } else if (d ==2) { // Up
                int farUp = ni -1;
                boolean farUpBlocked = (farUp <0 || (mask & (1L << (farUp*7 + nj))) !=0);
                boolean leftOpen = (nj -1 >=0 && (mask & (1L << (ni*7 + nj-1))) ==0);
                boolean rightOpen = (nj +1 <=6 && (mask & (1L << (ni*7 + nj+1))) ==0);
                prune = farUpBlocked && leftOpen && rightOpen;
            } else if (d ==3) { // Down
                int farDown = ni +1;
                boolean farDownBlocked = (farDown >6 || (mask & (1L << (farDown*7 + nj))) !=0);
                boolean leftOpen = (nj -1 >=0 && (mask & (1L << (ni*7 + nj-1))) ==0);
                boolean rightOpen = (nj +1 <=6 && (mask & (1L << (ni*7 + nj+1))) ==0);
                prune = farDownBlocked && leftOpen && rightOpen;
            }

            if (!prune) {
                solve(ni, nj, steps +1, newMask);
            }
        }
    }

    public static void main(String[] args) throws Exception {
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        solve(0, 0, 0, 0L);
        out.println(ans);
        out.close();
    }
}

Key Notes on the Changes:

  • The bitmask replaces the 2D array, cutting down on memory access latency dramatically.
  • Direction loops reduce code duplication, making the JIT's job easier to optimize the hot path.
  • Pruning conditions are precomputed with clear variables, avoiding redundant calculations and nested negations that can confuse the optimizer.
  • board is marked static final to let the JVM know it's immutable, enabling further optimizations.

These changes should shave off the extra 0.01 seconds needed to pass all test cases—bitmasking alone can give a significant speedup since it replaces array lookups with fast bitwise operations.

内容的提问来源于stack exchange,提问作者Krish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:56:24