Solitaire SPOJ的优化

时间:2015-09-18 11:18:32

标签: algorithm graph-algorithm graph-traversal breadth-first-search

问题代码:SOLIT
问题链接:http://www.spoj.com/problems/SOLIT/

我尝试解决SPOJ问题Solitaire。但是,我最终得到了TLE(超出时间限制)。我目前的解决方案大约需要2秒钟才能执行。我不知道如何进一步优化我的解决方案以减少时间。所以,在这方面我会感激不尽。

链接到我的解决方案:https://ideone.com/eySI91

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

class Solitaire {

    enum Direction {
        TOP, RIGHT, DOWN, LEFT;
    };

    static class Piece {
        int row, col;

        public Piece(int row, int col) {
            this.row = row;
            this.col = col;
        }

        @Override
        public boolean equals(Object o)
        {
            if (!(o instanceof Piece))
                return false;
            Piece p = (Piece)o;
            return (row==p.row && col==p.col);
        }

        @Override
        public int hashCode()
        {
            return (row*10 + col)%11;
        }
    }

    static class State {
        HashSet<Piece> pieces;

        public State() {
            pieces = new HashSet<>(11);
        }

        public State(State s) {
            pieces = new HashSet<>(11);
            for (Piece p: s.pieces)
                pieces.add(new Piece(p.row, p.col));
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof State))
                return false;
            State s = (State) o;
            if (pieces.size()!=s.pieces.size())
                return false;
            for (Piece p: pieces)
            {
                if (!s.pieces.contains(p))
                    return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            final int MOD = 1000000007;
            long code = 0;
            for (Piece p: pieces) {
                code = (code + p.hashCode())%MOD;
            }
            return (int) code;
        }

        @Override
        public String toString()
        {
            String res = "";
            for (Piece p: pieces)
                res = res + " (" + p.row + ", " + p.col + ")";
            return res;
        }

        public int getCloseness(State s)
        {
            int medianRow=0, medianCol=0, sMedianRow=0, sMedianCol=0;
            for (Piece p: pieces)
            {
                medianRow+=p.row;
                medianCol+=p.col;
            }
            medianRow/=4;
            medianCol/=4;
            for (Piece p: s.pieces)
            {
                sMedianRow+=p.row;
                sMedianCol+=p.col;
            }
            sMedianRow/=4;
            sMedianCol/=4;
            int closeness = ((sMedianCol-medianCol)*(sMedianCol-medianCol)) + ((sMedianRow-medianRow)*(sMedianRow-medianRow));
            return closeness;
        }
    }

    static State makeMove(State curr, Piece piece, Direction dir, HashSet<State> visited) {
        if (dir == Direction.TOP) {
            if (piece.row==1)
                return null;
            if (curr.pieces.contains(new Piece(piece.row-1, piece.col)))
            {
                if (piece.row==2 || curr.pieces.contains(new Piece(piece.row-2, piece.col)))
                    return null;
                else
                {
                    State newState = new State(curr);
                    newState.pieces.remove(new Piece(piece.row, piece.col));
                    newState.pieces.add(new Piece(piece.row-2, piece.col));
                    if (visited.contains(newState))
                        return null;
                    else
                        return newState;
                }
            }
            else
            {
                State newState = new State(curr);
                newState.pieces.remove(new Piece(piece.row, piece.col));
                newState.pieces.add(new Piece(piece.row-1, piece.col));
                if (visited.contains(newState))
                    return null;
                else
                    return newState;
            }
        }

        else if (dir == Direction.RIGHT) {
            if (piece.col==8)
                return null;
            if (curr.pieces.contains(new Piece(piece.row, piece.col+1)))
            {
                if (piece.col==7 || curr.pieces.contains(new Piece(piece.row, piece.col+2)))
                    return null;
                else
                {
                    State newState = new State(curr);
                    newState.pieces.remove(new Piece(piece.row, piece.col));
                    newState.pieces.add(new Piece(piece.row, piece.col+2));
                    if (visited.contains(newState))
                        return null;
                    else
                        return newState;
                }
            }
            else
            {
                State newState = new State(curr);
                newState.pieces.remove(new Piece(piece.row, piece.col));
                newState.pieces.add(new Piece(piece.row, piece.col+1));
                if (visited.contains(newState))
                    return null;
                else
                    return newState;
            }
        }

        else if (dir == Direction.DOWN) {
            if (piece.row==8)
                return null;
            if (curr.pieces.contains(new Piece(piece.row+1, piece.col)))
            {
                if (piece.row==7 || curr.pieces.contains(new Piece(piece.row+2, piece.col)))
                    return null;
                else
                {
                    State newState = new State(curr);
                    newState.pieces.remove(new Piece(piece.row, piece.col));
                    newState.pieces.add(new Piece(piece.row+2, piece.col));
                    if (visited.contains(newState))
                        return null;
                    else
                        return newState;
                }
            }
            else
            {
                State newState = new State(curr);
                newState.pieces.remove(new Piece(piece.row, piece.col));
                newState.pieces.add(new Piece(piece.row+1, piece.col));
                if (visited.contains(newState))
                    return null;
                else
                    return newState;
            }
        }

        else // dir == Direction.LEFT
        {
            if (piece.col==1)
                return null;
            if (curr.pieces.contains(new Piece(piece.row, piece.col-1)))
            {
                if(piece.col==2 || curr.pieces.contains(new Piece(piece.row, piece.col-2)))
                    return null;
                else
                {
                    State newState = new State(curr);
                    newState.pieces.remove(new Piece(piece.row, piece.col));
                    newState.pieces.add(new Piece(piece.row, piece.col-2));
                    if (visited.contains(newState))
                        return null;
                    else
                        return newState;
                }
            }
            else
            {
                State newState = new State(curr);
                newState.pieces.remove(new Piece(piece.row, piece.col));
                newState.pieces.add(new Piece(piece.row, piece.col-1));
                if (visited.contains(newState))
                    return null;
                else
                    return newState;
            }
        }
    }

    static boolean isReachableInEightMoves(State src, State target) {
        Queue<State> q = new LinkedList<>();
        HashSet<State> visited = new HashSet<>();
        int closeness = src.getCloseness(target);

        q.add(src);
        int moves = 0;
        while (!q.isEmpty() && moves <= 8) {
            int levelNodes = q.size();
            for (int i = 0; i < levelNodes; i++) {
                State curr = q.remove();
                if (curr.equals(target))
                    return true;
                if (moves==8)
                    continue;
                visited.add(curr);
                for (Piece p: curr.pieces)
                {
                    State newState = makeMove(curr, p, Direction.TOP, visited);
                    if (newState!=null)
                    {
                        int newCloseness = newState.getCloseness(target);
                        if (closeness>=newCloseness)
                        {
                            closeness=newCloseness;
                            visited.add(newState);
                            q.add(newState);
                        }
                    }
                    newState = makeMove(curr, p, Direction.RIGHT, visited);
                    if (newState!=null)
                    {
                        int newCloseness = newState.getCloseness(target);
                        if (closeness>=newCloseness)
                        {
                            closeness=newCloseness;
                            visited.add(newState);
                            q.add(newState);
                        }
                    }
                    newState = makeMove(curr, p, Direction.DOWN, visited);
                    if (newState!=null)
                    {
                        int newCloseness = newState.getCloseness(target);
                        if (closeness>=newCloseness)
                        {
                            closeness=newCloseness;
                            visited.add(newState);
                            q.add(newState);
                        }
                    }
                    newState = makeMove(curr, p, Direction.LEFT, visited);
                    if (newState!=null)
                    {
                        int newCloseness = newState.getCloseness(target);
                        if (closeness>=newCloseness)
                        {
                            closeness=newCloseness;
                            visited.add(newState);
                            q.add(newState);
                        }
                    }
                }
            }
            moves++;
        }
        return false;
    }

    public static void main(String[] args) throws IOException {
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(FileDescriptor.out), "ASCII"));
        CustomScanner sc = new CustomScanner();
        int t = sc.nextInt();
        long start = System.currentTimeMillis();
        while (t-- > 0) {
            State src = new State(), target = new State();
            for (int i = 0; i < 4; i++) {
                src.pieces.add(new Piece(sc.nextInt(), sc.nextInt()));
            }
            for (int i = 0; i < 4; i++) {
                target.pieces.add(new Piece(sc.nextInt(), sc.nextInt()));
            }
            if (isReachableInEightMoves(src, target))
                out.write("YES");
            else
                out.write("NO");
            out.newLine();
        }
        long end = System.currentTimeMillis();
        out.write("Time to execute = " + Double.toString((end-start)/1000d));
        out.flush();
    }

    static class CustomScanner {
        BufferedReader br;
        StringTokenizer st;

        public CustomScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        private String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }

        public String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }
}

有关实施的一些注意事项: -

  1. 我只是在做一个简单的bfs遍历,其中每个节点都是一个状态 董事会。
  2. 我定义了一个名为getCloseness()的函数,它测量两个不同状态的 closeness 。它基本上是两个状态的质心之间的距离的平方。状态的质心是每个部分的所有行值除以4的总和,对于列是相同的。
  3. 在计算每个州之后,我正在检查这个新州的接近程度是否小于或等于当前的接近程度。
  4. 如果它不接近,那么我将简单地丢弃新发现的状态。
  5. 如果它更近,那么我将更新closeness值并将此新状态插入队列以供将来处理。
  6. 当队列变空或发现与目标状态相同的状态时,此过程终止。
  7. 对于需要至少7次移动的情况,上述方法大约需要1-3秒。如果您能告诉我如何进一步优化此解决方案,我将不胜感激 根据问题的预期时间是0.896s。

0 个答案:

没有答案