分割矩阵 (二分范围[L,R))

   分割矩阵

                   (browine.c/cpp/pas)

【问题描述】

    有N*M的一个非负整数矩阵。现在要把矩阵分成A*B块。矩阵先水平地切A-1刀,把矩阵划分成A块。然后再把剩下来的每一块独立地切竖着B-1刀。每块的价值为块上的数字和。求一种方案,使得最小价值块的价值最大。

【输入格式】

    第一行四个整数N,M,A,B。

    接下来N行,每行M个非负整数。代表这个矩阵

【输出格式】

    一个数字。最小价值块的价值。

【样例输入】

5 4 4 2

1 2 21

3 1 1 1

2 0 1 3

1 1 1 1

1 1 11

【样例输出】

    3

 

样例解释见图片

【数据规模】

   1<=A<=N<=500

   1<=B<=M<=500

    其他数字小于4000。

 

 二分的同志请注意了

m=(l+r)/2 <-----这句是永远也枚不到L与R的


#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (500+10)
#define MAXM (500+10)
#define MAXT (2000000+10)
int n,m,t1,t2,a[MAXN][MAXM],sum[MAXN][MAXM]={0};
bool is_ok(int l,int r,int _m)
{
	int tot=0,p=0;
	for (int i=1;i<=m;i++)
	{
		tot+=sum[r][i]-sum[l-1][i];
		if (tot>=_m) {tot=0;p++;}
	}
	if (p>=t2) return 1;
	else return 0;
}
bool is_ok_(int _m)
{
	int p=0,l=1;
	for (int i=1;i<=n;i++)
	{
		if (is_ok(l,i,_m)) {l=i+1;p++;}
	}
	if (p>=t1) return 1;
	else return 0;
}
int main()
{
	freopen("browine.in","r",stdin);
	freopen("browine.out","w",stdout);
	scanf("%d%d%d%d",&n,&m,&t1,&t2);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
			sum[i][j]=sum[i-1][j]+a[i][j];
		}
	/*
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
		{
			printf("%d ",sum[i][j]);
		}
	*/
//	cout<<(is_ok_(4));
	int l=1,r=1,ans=0;
	for (int j=1;j<=m;j++) r+=sum[n][j];
	
	for (int i=1;i<=60;i++)
	{
		int m_=(l+r)/2;
		if (is_ok_(m_)) {l=ans=m_;}
		else r=m_;				
	}
	printf("%d\n",ans);
		
//	while (1);
	return 0;
}



 

### 关于PTA平台上最优二分检索树的实现 在讨论如何实现在PTA平台上的最优二分检索树之前,先理解什么是二分检索树以及它的工作原理。二分检索树是一种特殊的二叉搜索树,在这种结构中,节点按照特定顺序排列,使得左侧子树的所有键都小于根节点的键,而右侧子树的所有键都大于根节点的键[^3]。 为了构建一棵最优二分检索树,目标是最小化访问成本。给定一组关键字及其对应的查询频率,可以计算出不同路径长度加权后的总代价,并通过调整这些关键字的位置来优化这棵树的设计。具体来说: - 对于任何一颗包含`a1,a2,...,ak−1` 和 `E0,E1,…,Ek−1` 的左子树L,以及包含`ak+1, ak+2, ..., an` 和 `Ek, Ek+1, ..., En` 的右子树R而言,如果T是一棵最优二分检索树,则COST(L)和COST(R)也应分别为相应的最优解[^1]。 当考虑实际编程实现时,通常会采用动态规划的方法求解这个问题。下面给出一段Python代码作为参考,用于解决此类问题: ```python def optimal_bst(p, q, n): e = [[0]*(n+2) for _ in range(n+2)] w = [[0]*(n+2) for _ in range(n+2)] root = [[0]*(n+1) for _ in range(n+1)] for i in range(1, n+2): e[i][i-1], w[i][i-1] = q[i-1], q[i-1] for l in range(1, n+1): # Length of the subtree for i in range(1, n-l+2): j = i+l-1 e[i][j] = float('inf') w[i][j] = w[i][j-1]+p[j]+q[j] for r in range(i, j+1): t = e[i][r-1]+e[r+1][j]+w[i][j] if t < e[i][j]: e[i][j], root[i][j] = t, r return e[1][n], root ``` 此函数接收三个参数:`p` 表示内部结点的概率列表;`q` 表示外部结点(即叶子之间的间隔)的概率列表;`n` 则是指定了有多少个内部结点。该算法最终返回两个值——最小期望比较次数与记录最佳分割位置的矩阵。 对于具体的PTA题目实现方面,考虑到BinarySearch的具体需求,这里提供了一个简单的例子展示如何在一个已经建立好的二分检索树上执行查找操作: ```c++ Position BinarySearch(List L, ElementType X){ int low = 0; int high = length(L)-1; while(low <= high){ int mid = (low + high)/2; if(GetElementAt(L,mid)==X) return mid; // Found element else if(X<GetElementAt(L,mid)) high = mid - 1; else low = mid + 1; } return NotFound; // Element not found } ``` 这段C++代码实现了基本的二分查找逻辑,适用于静态数组或其他线性数据结构中的快速定位元素[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值