网易2017校招内推在线笔试编程题3

题目回忆
具体比较复杂,我按自己的理解(尚未知对否)简化为,将m x n数组,也就是田地,横竖各切三刀划分为16个分块,求如何切这6刀使得划分后的16块田地中最小价值的分块价值最大化,即最大化最小值问题。

解题思路
感觉应该是个动态规划问题,奈何不知如何解答(鄙人算法特别差),只能用暴力法解决,在这里也就是穷举法进行统计比对产生最优解。

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        //田地价值,记为m x n数组,这里为实验数据
        int[][] land = {{3,3,4,4,4},
                        {2,4,3,2,6},
                        {4,4,5,3,3},
                        {3,5,2,2,5},
                        {3,5,2,2,5},
                        {3,5,2,2,5},
                        {3,5,2,2,5},
                        {3,5,2,2,5}};

        Main main = new Main();
        main.distributeLandTo16(land);      
    }

    /**
     * 分成16块田地,横竖各切3刀
     * @param arr
     * @return
     */
    void distributeLandTo16(int[][] land) {
        int m = land.length, n = land[0].length;
        Map<String,Integer> allValues = new HashMap<String,Integer>(); //存放所有方案的各田地分块最小价值

        // 这里分成16块田地,横竖各切3刀,记x1 x2 x3 y1 y2 y3
        // 若第一横刀 x1 切 land[0] 和 land[1] 之间,则记 x1 值为0,以此类推,所以有范围如下:
        // 0 <= x1 < x2 < x3 < m-1,0 <= y1 < y2 < y3 < n-1
        int[] x = new int[5], y = new int[5];  //用数组存储,方便循环
        x[0] = y[0] = -1;
        x[4] = m-1;
        y[4] = n-1;

        //穷举暴力法
        for (x[1] = 0; x[1] < m-3; x[1]++) {
            for (x[2] = x[1]+1; x[2] < m-2; x[2]++) {
                for (x[3] = x[2]+1; x[3] < m-1; x[3]++) {
                    for (y[1] = 0; y[1] < n-3; y[1]++) {
                        for (y[2] = y[1]+1; y[2] < n-2; y[2]++) {
                            for (y[3] = y[2]+1; y[3] < n-1; y[3]++) {

                                int[] values = new int[16];  //存放该种分田方法的16个分块的价值
                                int cnt = 0;
                                //计算每个田地分块的总价值,共16块
                                for (int k = 0; k < 4; k ++) {
                                    for (int l = 0; l < 4; l ++) {
                                        //计算单个田地分块的价值
                                        for (int p = x[k]+1; p <= x[k+1]; p++){
                                            for (int q = y[l]+1; q <= y[l+1]; q++) {
                                                values[cnt] += land[p][q];
                                            }
                                        }
                                        cnt++;  //已计算完一个田地分块的价值
                                    }
                                }

                                //存储具体分地方案,比如“012 134”代表x1=0, x1=1, x2=2, y1=1, y2=3, y3=4
                                StringBuilder flag = new StringBuilder();
                                for(int k = 1; k <= 3; k++) {
                                    flag.append(x[k]);
                                }
                                flag.append(" ");
                                for(int k = 1; k <= 3; k++) {
                                    flag.append(y[k]);
                                }
                                allValues.put(flag.toString(), getMin(values));
                            }
                        }
                    }
                }
            }
        }
        //求最小值最大化的方案,在最小值集合中求得最大值
        Iterator it = allValues.keySet().iterator();
        String maxKey = "";
        int max = 0;
        while (it.hasNext()) {
            String str = (String) it.next();
            if (max < allValues.get(str)) {
                max = allValues.get(str);
                maxKey = str;
            }
        }
        System.out.println("最大化的最小值,即牛牛能得到的最大价值田地价值为:" + max);
        System.out.println("分割方式为:" + maxKey);

    }

    /**
     * 求arr数组中最小值
     * @param arr
     * @return
     */
    Integer getMin(int [] arr) {
        int min = arr[0];
        for (int num : arr) {
            if (min > num)
                min = num;
        }
        return min;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值