CS Mines Flood Fill问题- Java解决方案超时,而Cpp和python成功(性能改进)

46qrfjad  于 2023-05-05  发布在  Java
关注(0)|答案(1)|浏览(83)

致力于解决这个问题
https://mines20.kattis.com/problems/mines20.paintbucket
使用TreeSet的Java解决方案超时,时间限制小于3秒

public class PaintBucketCSMinesSolution {

    public static void main(String[] args) throws IOException {
        // maintain distinct list of points that have been visited
        Set<int[]> exploredSet = new TreeSet<>(
                Comparator.comparingInt((int[] el) -> el[1]).thenComparingInt(el -> el[0]));
        int W;
        int H;
        int X;
        int Y;
        int[][] picture;
        BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(r.readLine());
        W = Integer.parseInt(st.nextToken());
        H = Integer.parseInt(st.nextToken());
        X = Integer.parseInt(st.nextToken());
        Y = Integer.parseInt(st.nextToken());
        picture = new int[H][W];
        for (int i = 0; i < H; i++) {
            st = new StringTokenizer(r.readLine());
            for (int j = 0; j < W; j++) {
                picture[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        int color = picture[Y][X];

        Stack<int[]> toExploreStack = new Stack<>();

        toExploreStack.add(new int[] { X, Y });

        while (!toExploreStack.isEmpty()) {
            int[] point = toExploreStack.pop();
            int px = point[0];
            int py = point[1];
            // System.out.println(exploredSet.contains(point));
            boolean execute = true;

            if (exploredSet.contains(point)) {
                execute = false;
            }

            if (execute) {
                exploredSet.add(point);

                if (px > 0 && picture[py][px - 1] == color) {
                    toExploreStack.add(new int[] { px - 1, py });
                }

                if (px < (W - 1) && picture[py][px + 1] == color) {
                    toExploreStack.add(new int[] { px + 1, py });
                }

                if (py > 0 && picture[py - 1][px] == color) {
                    toExploreStack.add(new int[] { px, py - 1 });
                }

                if (py < (H - 1) && picture[py + 1][px] == color) {
                    toExploreStack.add(new int[] { px, py + 1 });
                }
            }

        }
        // exploredSet.sort(Comparator.comparingInt((int[] el) ->
        // el[1]).thenComparingInt(el -> el[0]));
        // Sorting HashSet using List

        for (int[] v : exploredSet) {
            System.out.println(v[0] + " " + v[1]);
        }

    }
}

Python中的解决方案在2.65秒内成功完成所有测试用例

W, H,X,Y = map(int, input().split())

picture=[]

for y in range(H):
    picture.append([int(c) for c in input().split()])

#print(picture)
# implement a stack
to_explore = [(X , Y)]
explored=set()
color = picture[Y][X]
#print("color" , color)

while len(to_explore) >0:
    px, py = to_explore.pop()

    if(px, py) in explored:
        continue
    explored.add((px, py))

    if (px > 0 and picture[py][px - 1] == color) :
       to_explore.append( (px - 1, py ))

    if (px < (W - 1) and picture[py][px + 1] == color) :
        to_explore.append((px + 1, py ))

    if (py > 0 and picture[py - 1][px] == color) :
        to_explore.append( (px, py - 1) )

    if (py < (H - 1) and picture[py + 1][px] == color) :
        to_explore.append(( px, py + 1) )
        
for x,y in sorted(explored, key=lambda x: (x[1], x[0])):
    print(x, y)

CPP溶液在2.05秒内完成

#include <algorithm>
#include <array>
#include <iostream>
#include <set>
#include <stack>
#include <vector>

int main() {
    // comparison to sort the set naturally on inserting elements
    const auto compare = [](const std::array<int, 2> &lhs,
                            const std::array<int, 2> &rhs) {
        return lhs[1] < rhs[1] || (lhs[1] == rhs[1] && lhs[0] < rhs[0]);
    };

    // set to maintain unique elements as it is used for lookup to check if we have visited the node already
    std::set<std::array<int, 2>, decltype(compare)> exploredSet(compare);
    // std::set<std::array<int, 2>> exploredSet;
    int W;
    int H;
    int X;
    int Y;
    // std::vector<std::vector<int>> picture;
    std::cin >> W;
    std::cin >> H;
    std::cin >> X;
    std::cin >> Y;
    int picture[W][H];
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            std::cin >> picture[i][j];
        }
    }
    int color = picture[Y][X];

    std::stack<std::array<int, 2>> toExploreStack;
    toExploreStack.push({X, Y});

    while (!toExploreStack.empty()) {
        std::array<int, 2> point = toExploreStack.top();
        toExploreStack.pop();
        int px = point[0];
        int py = point[1];
        bool execute = true;

        // plain for loop was slow, this method is fast
        if (exploredSet.count(point) == 1) {
            execute = false;
        }

        if (execute) {
            exploredSet.insert(point);

            if (px > 0 && picture[py][px - 1] == color) {
                toExploreStack.push({px - 1, py});
            }

            if (px < (W - 1) && picture[py][px + 1] == color) {
                toExploreStack.push({px + 1, py});
            }

            if (py > 0 && picture[py - 1][px] == color) {
                toExploreStack.push({px, py - 1});
            }

            if (py < (H - 1) && picture[py + 1][px] == color) {
                toExploreStack.push({px, py + 1});
            }
        }
    }

    for (std::array<int, 2> v : exploredSet) {
        std::cout << v[0] << " " << v[1] << std::endl;
    }
}

请帮助优化Java解决方案。我已经没有办法了。
已经试过了

  • HashMap并在end中排序
  • HashSet并在最后排序。

同样令人惊讶的是,在这种情况下,Python能够比Java实现更快地完成。

a11xaf1n

a11xaf1n1#

TreeSet与自定义比较器结合使用时,开销似乎太大。HashSet版本应该可以工作,并且与其他版本的逻辑相同。你只需要处理对象就可以得到正确的hashCode。您可以尝试将相关行更改为:

Set<List<Integer>> exploredSet = new HashSet<>();
...
if (exploredSet.contains(List.of(px, py))) {
...
exploredSet.add(List.of(px, py));
...
for (List<Integer> v : exploredSet) {
     System.out.println(v.get(0) + " " + v.get(1));
}

相关问题