最大子矩阵
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定一个NxM的矩阵A和一个整数K,小Hi希望你能求出其中最大(元素数目最多)的子矩阵,
并且该子矩阵中所有元素的和不超过K。
输入
第一行包含三个整数N、M和K。
以下N行每行包含M个整数,表示A。
对于40%的数据,1 <= N, M <= 10
对于100%的数据,1 <= N, M <= 250 ; 1 <= K <= 2147483647 ; 1 <= Aij <= 10000
输出
满足条件最大的子矩阵所包含的元素数目。如果没有子矩阵满足条件,输出-1。
样例输入
3 3 9
1 2 3
2 3 4
3 4 5
样例输出
4
思路:
首先先画个图
这个只画了从0.0开始的子矩阵
我的思路是首先通过排序
让一维排序有序
再让一维数组中最小元素来排列二维数组
这样实现从左上递增到做小
然后通过一个辅助同样大小的数组
让每个位置都成为0.0到该位置矩阵的元素的和
红色位置就是矩阵的和
也就是说可以在求和的过程中,判断是否大于k
大于k了那就跳出
//数据量:1 <= N, M <= 250 ; 1 <= K <= 2147483647 ; 1 <= Aij <= 10000
//时间复杂度:O(N^M)
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
long K = sc.nextLong();
long[][] arr = new long[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
arr[i][j] = sc.nextLong();
}
Arrays.sort(arr[i]);//N*NlogN
}
long now = System.currentTimeMillis();
sort(arr,0,N-1);//NlogN
//排序之后左上的节点不需要动
//左上最小,右小最大
//左边比右边小
long maxCount = 0;
long[][] help = new long[N][M];
l1:for (int i = 0; i < N; i++) {//N^M
for (int j = 0; j < M; j++) {
if(i==0&&j==0) {//第一个元素是为本身
help[i][j] = arr[i][j];
}
else if(i==0 && j!=0) {//第一行
help[i][j] = arr[i][j] + help[i][j-1];
}
else if(j==0 && i!=0) {//第一列
help[i][j] = arr[i][j] + help[i-1][j];
}
else {
//后面为上右相加这样当前位置就是0.0到当前的总和
help[i][j] = arr[i][j] + help[i-1][j] + help[i][j-1]-help[i-1][j-1];
//一定要减去他左上一个对角位置的值,因为上元素的和包括左上角值,左元素也包括左上角值,那么就重复了
//这个地方一定要验算最后一个元素的和是不是整个矩阵的和
}
int t = (i+1)*(j+1);//每次都把元素个数统计
if(help[i][j] > K) {//大于了k跳出
break l1;
}
else if(maxCount<t) {//如果当前的元素大于最大的计数那么赋值给他
maxCount = t;
}
}
}
System.out.println(maxCount);
System.out.println(System.currentTimeMillis()-now+"ms");
}
//根据二维数组第一个元素排序
static void sort(long[][] arr,int begin,int end) {
if(begin < end) {
if (end-begin+1<7) {//排序元素小于7改插入排序
for (int i = begin+1; i <= end; i++) {
long val = arr[i][0];
long[] t = arr[i];
int index = i - 1;
while(index > -1 && val < arr[index][0]) {
arr[index+1] = arr[index];
index--;
}
arr[index+1] = t;
}
}else {
int p = Mid(arr,begin,end);
sort(arr, begin, p-1);
sort(arr, p+1, end);
}
}
}
static int Mid(long[][] arr, int begin, int end) {
//三点优化
int mid = (begin + end) >>1;
if (arr[begin][0] > arr[mid][0] && arr[begin][0] < arr[end][0]) {
mid = begin;
}else if(arr[end][0] > arr[begin][0] && arr[end][0] < arr[mid][0]) {
mid = end;
}
long[] t = arr[begin];arr[begin] = arr[mid];arr[mid] = t;
long poivt = arr[begin][0];
int left = begin+1;
int right = end;
while(left<=right) {
if(left<=right && arr[left][0]<=poivt)left++;
if(left<=right && arr[right][0]>poivt)right--;
if(left<right) {
t = arr[left];arr[left] = arr[right];arr[right] = t;
}
}
t = arr[begin];arr[begin] = arr[right];arr[right] = t;
return right;
}