火力网问题的Java实现

题目

        在一个n*n的网格里,每个网格可能称为“墙壁”和“街道”。现在在街道放置碉堡,每个碉堡可以向上下左右四个方向开火。子弹射程无限远,墙壁可以阻挡子弹。问最多能放置多少个碉堡,使他们彼此不会互相摧毁。

算法描述

        算法中用二维int数组表示网格,每个网格都有其索引值,对n*n的网格,从左到右,从上到下,索引值依次为0~n*n-1。数组中0表示道路,-1表示墙壁,1表示碉堡,如果出现其他数字,则该数组非法。

        算法思路是深度优先+回溯算法,从索引0开始,一直到n*n-1,选择是否插入碉堡。如果在索引index时能够插入碉堡,则碉堡计数quantity+1,index+1并继续调用此函数,直至结束后再在index位置取消插入碉堡同时碉堡计数quantity-1,index+1并继续调用,这个过程就是回溯过程。如果在索引index时不能插入碉堡,则直接index+1继续调用本函数。如果index大于最大值时,表示方格遍历完成,将此时的碉堡数量与最大数量进行比较,如果此时quantity=maxQuantity则记录此时的布局状态在ArrayList<int [][]> result中,如果此时quantity>maxQuantity则更新maxQuantity,删除之前的布局记录,并将此时的布局记录到ArrayList<int [][]> b中。

        boolean check(int[][] a)用于安全性检查,检查数组a是否合法。

        void show(int[][] a)用于打印a的布局|表示边界,═表示墙,*表示碉堡,空白表示道路

        int[][] createBlock(int size, int... wall_location)用于创建一个布局,size表示布局的边长,后面的int参数用于表示墙壁的索引值,如果只有第一个参数则表示创建没有墙壁的布局。函数返回该布局的数组。

        boolean setFort(int[][] a, int fort_location)用于在布局a中指定位置放置碉堡,如果放置成功,返回true,防止失败返回false。

        void fillFort(int[][] a, int index)为上文提到的深度优先+回溯算法的函数,具体思想上文有详细描述。

代码实现

import java.util.ArrayList;

public class Problem3 {
    //0表示道路,-1表示墙,1表示碉堡
    private static int maxQuantity = 0;//用于记录最多的碉堡数量
    private static int quantity = 0;//用于记录已安插碉堡的数量
    private static ArrayList<int[][]> result = new ArrayList<>();//用于存储最优解

    private static boolean check(int[][] a) {
        //检查网格是否合法,即是否为n*n,是否仅有-1,0,1
        for (int[] ints : a) {//对传入的数组进行参数合法性检查
            if (ints.length != a.length) {//数组应为n*n
                return false;
            } else {//数组内不能出现不是-1,0,1的数字
                for (int x : ints) {
                    if (x != 0 && x != -1 && x != 1) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private static void show(int[][] a) {
        //打印指定网格内的墙壁,堡垒道路情况,|表示边界,═表示墙,*表示碉堡,空白表示道路
        if (!check(a)) {
            throw new IllegalArgumentException("传入参数不合法");
        }
        //对a进行合法校验,是否满足网格要求
        System.out.print(" ");
        for (int i = 0; i < a.length; i++) {
            System.out.print(" _ ");
        }
        System.out.println("");
        for (int[] x : a) {
            System.out.print("|");
            for (int i : x) {
                switch (i) {
                    case -1:
                        System.out.print(" ═ ");
                        break;
                    case 0:
                        System.out.print("   ");
                        break;
                    case 1:
                        System.out.print(" * ");
                }
            }
            System.out.println("|");
        }
        System.out.print(" ");
        for (int i = 0; i < a.length; i++) {
            System.out.print(" ˉ ");
        }
        System.out.println("");
    }

    private static int[][] createBlock(int size, int... wall_location) {
        //创建一个网格和其中的墙,size为网格大小,wall_location表示墙的位置
        if (size <= 0) {
            throw new IllegalArgumentException("请传入大于零的网格尺寸");
        }
        //进行参数合法性校验
        int[][] a = new int[size][size];
        for (int i : wall_location) {
            if (i < 0 || i >= size * size) {
                throw new IllegalArgumentException("墙壁位置越界");
            } else {
                a[i / size][i % size] = -1;
            }
        }
        return a;
    }

    private static int[][] createBlock(int size) {
        //创建一个无墙网格,size为网格大小,无wall_location表示没有墙
        if (size <= 0) {
            throw new IllegalArgumentException("请传入大于零的网格尺寸");
        }
        //进行参数合法性校验
        int[][] a = new int[size][size];
        return a;
    }

    private static boolean setFort(int[][] a, int fort_location) {
        if (!check(a)) {
            throw new IllegalArgumentException("网格不规范");
        } else if (fort_location < 0 || fort_location >= a.length * a.length) {
            throw new IllegalArgumentException("碉堡位置越界");
        }
        int x = fort_location / a.length;
        int y = fort_location % a.length;//插入碉堡的横纵坐标
        if (a[x][y] != 0) {
            return false;
        }//如果当前位置不是空白,则不能插入,返回false;
        //如果是空白,判断其上下左右
        for (int i = x - 1; i >= 0; i--) {//判断其上方
            if (a[i][y] == -1) {
                break;
            } else if (a[i][y] == 1) {
                return false;
            }
        }
        for (int i = x + 1; i < a.length; i++) {//判断其下方
            if (a[i][y] == -1) {
                break;
            } else if (a[i][y] == 1) {
                return false;
            }
        }
        for (int j = y - 1; j >= 0; j--) {//判断其左方
            if (a[x][j] == -1) {
                break;
            } else if (a[x][j] == 1) {
                return false;
            }
        }
        for (int j = y + 1; j < a.length; j++) {//判断其右方
            if (a[x][j] == -1) {
                break;
            } else if (a[x][j] == 1) {
                return false;
            }
        }
        //全都没问题则添加碉堡并返回true
        a[x][y] = 1;
        return true;
    }

    private static void fillFort(int[][] a, int index) {
        if (!check(a)) {
            throw new IllegalArgumentException("请传入合法的网格");
        } else if (index < 0 || index > a.length * a.length) {
            throw new IllegalArgumentException("请传入合法的index");
        }
        if (index == a.length * a.length) {
            if (quantity >= maxQuantity) {
                int[][] m = new int[a.length][a.length];
                for (int i = 0; i < a.length; i++) {
                    for (int j = 0; j < a.length; j++) {
                        m[i][j] = a[i][j];
                    }
                }
                if (quantity > maxQuantity) {
                    maxQuantity = quantity;
                    result.clear();
                }
                result.add(m);
            }
        } else {
            if (setFort(a, index)) {
                quantity++;
                fillFort(a, index + 1);
                a[index / a.length][index % a.length] = 0;
                quantity--;
            }
            fillFort(a, index + 1);
        }
    }

    public static void main(String[] args) {
        int[][] a = createBlock(4, 1, 8, 9);
        //创建网格和墙壁,该参数表示4*4的网格中,1,8,9位置为墙
        System.out.println("地形如下:");
        show(a);//打印未安插碉堡的地图

        fillFort(a, 0);
        //对创建的网格进行填充,得到的最多碉堡数量记录在maxQuantity中,填充方式记录在result中
        System.out.println("最多安插" + maxQuantity + "个碉堡,共找到" + result.size() + "组最优解,它们分别是:");
        for (int i = 0; i < result.size(); i++) {
            show(result.get(i));
        }
    }
}

运行结果

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值