【算法】网易2017校园招聘笔试程序题(分田地)

题目

牛牛和15个朋友玩打土豪分田地的游戏,牛牛决定让你来分田地,地主的田地可以看成是一个矩形,每个位置有一个价值。分割田地的方法是横竖各切三刀,分成16份,作为领导干部,牛牛总是会选择其中总价值最小的一份田地,作为牛牛最好的朋友,你希望牛牛取得的田地的价值和尽可能大,你知道这个值最大可以是多少吗?

输入描述

每个输入包含1个测试用例。每个测试用例的第一行包含两个整数n和m(1 <= n,m <= 75),表示田地的大小,接下来的n行,每行包含m个0-9之间的数字,表示每块位置的价值。

输出描述

输出一行表示牛牛所能取得的最大的价值。

结果

输入例子
4 4
3 3 3 2
3 2 3 3
3 3 3 2
2 3 2 3
输出例子
2

算法思路

咋一看这个题目不是傻逼嘛,只求矩阵最小值不就可以么。。。细思之后才发现自己傻逼。题目的意思是对于m*n的矩阵,横竖三刀,也就是十六份中,牛牛得最小值。但是因为有不同的切法,所以在所有分法中,牛牛要得到最小值中最大的那个,因为他朋友希望牛牛能拿的价值尽可能大。
那这个题目如何解呢?因为横竖切法太多了,都不知道如何下手,暴力破解也不是很好办啊。但是冷静之后想了下,其实思路我觉得也挺简单。
1)就是对于m*n的矩阵,首先找到最小值的那块,你想你希望牛牛拿的多,那这块肯定是要和它周边分在一起的,那对于最小这块可以和它分在一起的,无非就是向上合并,或者向下合并,或者向左合并,或者向右合并嘛,这样就得到一个行或者列少一行的新矩阵。
2)对于新矩阵再次找最小块,然后是向上合并,或者向下合并,或者向左合并,或者向右合并,完全就是上面的一个新轮回。
3)直到矩阵合并为4*4的矩阵,其中最小的就是牛牛获得最小值。
需要注意的是,每一次合并都不能确定一定是往某一个方向合并,所以必须每个方向都合并,这样每种情况下最后会产生不一样的4*4矩阵,也就是能得到若干最小值,而牛牛最终得到的价值就是这些最小值中最大的。

算法实现

public class Main{
    public static int minVal;
public static void main(String[] args) {
   Scanner sc = new Scanner(System.in); 
   int n = sc.nextInt()-1;//N行
   int m = sc.nextInt()-1;//M列
   int matrix[][] = new int[n+1][m+1];
   int minpos[]=new int[2];//记录矩阵中最小值的位置
   for(int i=0;i<=m;i++){
        for(int j=0;j<=n;j++){
            matrix[i][j]=sc.nextInt();
        }
    }

   getMinpos(matrix,m,n,minpos);//获取矩阵中最小值位置
   minVal=matrix[minpos[0]][minpos[1]];//初始化牛牛获得的最小价值
    System.out.println("所有分法:");
   getMaxVal(matrix,m,n,minpos);//分田过程
   System.out.println("最终牛牛获得的价值:"+minVal);//输出牛牛获得的价值
}

private static void getMaxVal(int[][] matrix, int m, int n, int[] minpos) {
    int oldMatrix[][] = new int[m+1][n+1];
    oldMatrix=matrix;//保存原矩阵,回溯返回到这时还需要用原来的矩阵而不是被子过程改变的矩阵
    int m0 = minpos[0];
    int n0 = minpos[1];
    //最后得到4*4返回
    if(m==n&&m==3){
        for(int i=0;i<=3;i++){
            System.out.println(java.util.Arrays.toString(matrix[i]));
        }
        System.out.println();
        return;
    }
    //向上合并
    if(m0>0&&m>3){
        matrix=mergeMatrix(matrix,m,n,m0-1,n,minpos,1);
        getMaxVal(matrix,matrix.length-1,matrix[0].length-1,minpos);
    }
    matrix=oldMatrix;
    //向下合并
    if(m0<m&&m>3){
        matrix=mergeMatrix(matrix,m,n,m0,n,minpos,1);
        getMaxVal(matrix,matrix.length-1,matrix[0].length-1,minpos);
    }
    matrix=oldMatrix;
    //向左合并
    if(n0>0&&n>3){
        matrix=mergeMatrix(matrix,m,n,m,n0-1,minpos,-1);
        getMaxVal(matrix,matrix.length-1,matrix[0].length-1,minpos);
    }
    matrix=oldMatrix;
    //向右合并
    if(n0<n&&n>3){
        matrix=mergeMatrix(matrix,m,n,m,n0,minpos,-1);
        getMaxVal(matrix,matrix.length-1,matrix[0].length-1,minpos);
    }
}

private static int[][] mergeMatrix(int[][] matrix, int m, int n,int mergem,int mergen, int[] minpos,int flag) {
    int[][] temp=null;
    if(flag==1){//向上合并 或 向下合并
         temp = new int[m][n+1];
        for(int i=0;i<=m;i++){
            for(int j=0;j<=n;j++){
                if(i<mergem){
                    temp[i][j] = matrix[i][j];
                }
                else if(i==mergem){
                    temp[i][j] = matrix[i][j]+matrix[i+1][j];
                }else{
                    temp[i-1][j] = matrix[i][j];
                }
            }
            if(i==mergem){
                i++;
            }
        }
    }else if(flag==-1){//向左合并 或 向右合并
        temp = new int[m+1][n];
        for(int i=0;i<=m;i++){
            for(int j=0;j<=n;j++){
                if(j<mergen){
                    temp[i][j]=matrix[i][j];
                }
                else if(j==mergen){
                    temp[i][j]=matrix[i][j]+matrix[i][j+1];
                    j++;
                }else{
                    temp[i][j-1]=matrix[i][j];
                }
            }
        }
    }
    //合并后的矩阵求其中最小的位置
   getMinpos(temp,temp.length-1,temp[0].length-1,minpos);
   return temp;
}

//获取矩阵最小值位置
private static void getMinpos(int[][] matrix,int m,int n,int[] minpos) {
    int min = Integer.MAX_VALUE;
    for(int i=0;i<=m;i++){ 
        for(int j=0;j<=n;j++){
            if(matrix[i][j]<min){
                min=matrix[i][j];
                minpos[0]=i;
                minpos[1]=j;
            }
        }
    }
    if(minVal<min){
        minVal=min;
    }
}

}

示例

注意我的输入矩阵是带空格的,原题是不带空格,所以还需要以字符串输入再切分。

 5 5
3 3 3 2 2
3 2 2 3 3
3 3 3 3 2
1 1 1 1 1
2 2 2 2 2
所有分法:
[3, 3, 5, 2]
[3, 2, 5, 3]
[4, 4, 8, 3]
[2, 2, 4, 2]

[3, 3, 3, 4]
[3, 2, 2, 6]
[4, 4, 4, 7]
[2, 2, 2, 4]

[3, 3, 5, 2]
[3, 2, 5, 3]
[3, 3, 6, 2]
[3, 3, 6, 3]

[3, 3, 3, 4]
[3, 2, 2, 6]
[3, 3, 3, 5]
[3, 3, 3, 6]

[6, 3, 2, 2]
[5, 2, 3, 3]
[8, 4, 4, 3]
[4, 2, 2, 2]

[6, 3, 2, 2]
[5, 2, 3, 3]
[6, 3, 3, 2]
[6, 3, 3, 3]

最终牛牛获得的价值:2

结语

因为牛客网还没出真题oj所以无法知道是否通过,如果有人发现算法有误,欢迎拍砖!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值