版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37667021/article/details/82457601
网易_分田地
java代码
4 4
3332
3233
3332
2323
输出
2
题意:题目意思是将一块举行分成16块,然后牛牛取得其中最小的那一块,但是由于横竖都切三刀的位置不一样即切法不同,就会得出不同的结果,现在求的是这些分法中牛牛可以取得的最大值。
思路:二分查找+4层for循环嵌套
反正牛牛是取得分法中最小的一块,如果要使分得的价值尽可能大,难么这16块要尽量均匀,这样才能取得最大值。设结果为ans,那么ans一定介于0到sum[n][m],sum用来记录价值,左上角为(0,0),右下角为(n,m),sum[n][m]表示的是整个矩形的价值。我们用二分法不断去逼近最终的结果ans,对于中间的mid,我们要测试是否可以找到一种分法使得分成的16块均大于等于mid值,用这个判断来逼近最终的结果ans。
那么关键是如何去判断是否可以找到一种分法使得分成的16块均大于等于mid值呢?
如果横竖切的每一刀都进行for循环遍历的话,这个复杂度太高了。那么我们可以只遍历横切的三刀,这样就把矩形分成了4个横着的矩形,然后之用一层for循环遍历竖切得一刀, 如果当前列的前一刀列和横着着三刀所在行构成的四个区域,每一个区域的价值和都大于mid,则在此处切一刀,接着继续寻找下一刀,如果可以找到4刀以上就返回true,否则false。再解释下着4个区域:就是新的竖着切的一刀与前一个竖着切得一刀之间的那4个区域
import java.util.*;
import java.io.*;
public class Main {
public static int cal(int x1,int y1,int x2,int y2,int[][] sum)
{
return sum[x2][y2]-sum[x1][y2]-sum[x2][y1]+sum[x1][y1];
}
public static boolean judge(int value,int n,int m,int[][] sum)
{
int i,j,k,t;
int cnt;
int lasttime;
for(i=1;i<=n-3;i++)
{
for(j=i+1;j<=n-2;j++)
{
for(k=j+1;k<=n-1;k++)
{
cnt=0;
lasttime=0;
for(t=1;t<=m;t++)
{
if( cal(0,lasttime,i,t,sum)>=value&&
cal(i,lasttime,j,t,sum)>=value&&
cal(j,lasttime,k,t,sum)>=value&&
cal(k,lasttime,n,t,sum)>=value
){
cnt++;
lasttime=t;
}
}
if(cnt>=4)return true;
}
}
}
return false;
}
public static void main(String args[]) {
int i,j,k,d;
Scanner cin=new Scanner(System.in);
while (cin.hasNext())
{
int n=cin.nextInt();
int m=cin.nextInt();
int[][] matrix=new int[n+2][m+2];
for ( i=1;i<=n ;i++ )
{
String str=cin.next();
for ( j=1;j<=m;j++ )
{
matrix[i][j]=str.charAt(j-1)-'0';
}
}
// System.out.println("ok");
int[][] sum=new int[n+3][m+3];
for ( i=1;i<=n ;i++ )
{
for (j=1;j<=m ;j++ )
{
sum[i][j]=sum[i-1][j]+ sum[i][j-1]-sum[i-1][j-1]+matrix[i][j];
}
}
int LL=0,RR=sum[n][m],res=0;
while (LL<=RR)
{
int mid=(LL+RR)/2;
if (judge(mid,n,m,sum))
{
LL=mid+1;
res=mid;
}
else
{
RR=mid-1;
}
}
System.out.println(res);
}
cin.close();
}
}
/*
输入
4 4
3332
3233
3332
2323
输出
2
* */