挑战程序设计竞赛(算法和数据结构)——19.2九宫格拼图问题的JAVA实现

Posted 小乖乖的臭坏坏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了挑战程序设计竞赛(算法和数据结构)——19.2九宫格拼图问题的JAVA实现相关的知识,希望对你有一定的参考价值。

题目&解题思路:


代码:

import java.io.PushbackInputStream;
import java.util.*;

public class Puzzle_9 
    public static final int  N = 3;
    public static final int N2 = 9;
    public static final int dx[] = -1, 0, 1, 0;
    public static final int dy[] = 0, -1, 0, 1;
    public static final char dir[] = 'u', 'l', 'd', 'r';

    public static class Puzzle implements Comparable 
        int f[] = new int[N2];
        int space;
        String path;

        @Override
        public int compareTo(Object obj)
            Puzzle p = (Puzzle)obj;
            int cnt = 0;
            for (int i=0;i<N2;i++)
                if(p.f[i]==this.f[i])cnt++;
                else
                    return -1;
                
            
            if (cnt==9)
                return 0;
            
            else
                return -1;
            
        
    

    //如果第i个元素对应的不是(i+1),那么就返回false
    public static boolean isTarget(Puzzle p)
        for (int i=0;i<N2;i++)
            if(p.f[i]!=(i+1))
                return false;
            
        
        return true;
    

    public static String bfs(Puzzle s)
        ArrayDeque<Puzzle> Q = new ArrayDeque<>();
        HashSet<Puzzle> V = new HashSet<>();
        Puzzle u = new Puzzle();
        Puzzle v = new Puzzle();
        s.path = "";//将传入的路径设置为空
        Q.addLast(s);//入队
        V.add(s);//将s的状态添加进入历史访问集合

        while (!Q.isEmpty())
            u = copyPuzzle(Q.peek());
            Q.removeFirst();
            if(isTarget(u))return u.path;//如果完成目标了,则返回u的路径
            int sx = u.space/N;//用于对当前空格的定位
            int sy = u.space%N;
            for (int r=0;r<4;r++)
                int tx = sx + dx[r];//设置4个方位的移动
                int ty = sy + dy[r];
                if(tx<0||ty<0||tx>=N||ty>=N)continue;
                v = copyPuzzle(u);
                
                //移动空格
                int temp = v.f[u.space];
                v.f[u.space] = v.f[tx*N+ty];
                v.f[tx*N+ty] = temp;
                //设置空格位置
                v.space = tx*N+ty;
                
                //判断这个状态历史上是否发生,如果发生就跳过,没发生就执行:
                if(!isContain(V,v))
                    V.add(v);//将当前状态加入历史记录集合
                    v.path += dir[r];//将移动操作添加到其路径中
                    Q.addLast(v);//将当前状态入队等待操作
                
            
        
        return "unsolvable";
    

    public static boolean isContain(HashSet<Puzzle> V, Puzzle v)
        Iterator<Puzzle> it = V.iterator();
        while(it.hasNext())
            Puzzle element = it.next();
            if(element.compareTo(v)==0)
                return true;
            ;
        
        return false;
    

    public static Puzzle copyPuzzle(Puzzle p)
        Puzzle p1 = new Puzzle();
        p1.space = p.space;
        p1.path = p.path;
        for (int i=0;i<N2;i++)
            p1.f[i] = p.f[i];
        
        return p1;
    


    public static void main(String[] args) 
        Scanner cin = new Scanner(System.in);
        Puzzle in = new Puzzle();
        for (int i=0;i<N2;i++)
            in.f[i] = cin.nextInt();
            if(in.f[i] == 0)
                in.f[i] = N2;
                in.space = i;
            
        
        String ans = bfs(in);
        System.out.println(ans.length());
    

输入:

1 3 0
4 2 5
7 8 6

输出:

4

这次的代码有很多值得玩味的地方,虽然耽误了很多时间,踩了很多坑,也总结很多经验。

1.目的:想要用对象2存入对象1中的所有值。
错误做法:将对象2赋值给对象1。
结果:更改对象2时,对象1也会同时更改。
原因:将对象2赋值给对象1的动作实际上是把对象2的地址赋给对象1,因此无论操作对象1还是对象2都是操作的同一片内存空间。
解决方案:为对象1开辟一份新的内存空间,将对象2中所有的值赋给对象1,甚至是对象1中的数组也要以元素为单位一一赋值

示例代码:

public static Puzzle copyPuzzle(Puzzle p)
        Puzzle p1 = new Puzzle();
        p1.space = p.space;
        p1.path = p.path;
        for (int i=0;i<N2;i++)
            p1.f[i] = p.f[i];
        
        return p1;
    

2.目的:如何自定义比较两个对象是否一致。
错误做法:再写一个函数比较,很麻烦。
解决方案:实现Comparable接口,并重写compareTo方法,这样就可以定义一个比较器,从而比较别的对象是不是和自己相同

示例代码:

    public static class Puzzle implements Comparable 
        int f[] = new int[N2];
        int space;
        String path;

        @Override
        public int compareTo(Object obj)
            Puzzle p = (Puzzle)obj;
            int cnt = 0;
            for (int i=0;i<N2;i++)
                if(p.f[i]==this.f[i])cnt++;
                else
                    return -1;
                
            
            if (cnt==9)
                return 0;
            
            else
                return -1;
            
        
    

3.对于一个ArrayDeque队列,添加删除元素时,最好用addLast,removeFirst这样的函数,否则使用push、add、remove、pop就不确定从哪头插入元素删除元素了,这就失去了队列的意义,也是今天卡了很久的原因

以上是关于挑战程序设计竞赛(算法和数据结构)——19.2九宫格拼图问题的JAVA实现的主要内容,如果未能解决你的问题,请参考以下文章

挑战程序设计竞赛(算法和数据结构)——分割(下)&快速排序的JAVA实现

挑战程序设计竞赛(算法和数据结构)——7.1归并排序JAVA实现

挑战程序设计竞赛(算法和数据结构)——16.13线段相交问题(曼哈顿算法)的JAVA实现

挑战程序设计竞赛(算法和数据结构)——3.6希尔排序的JAVA实现

挑战程序设计竞赛(算法和数据结构)——3.6希尔排序的JAVA实现

挑战程序设计竞赛(算法和数据结构)——7.2分割(上)JAVA实现