洛谷P1790 矩形分割

题目描述
有一个长为a,宽为b的矩形(1≤a≤6,2≤b≤6)。可以把这个矩形看作是a*b个小方格。

我们现在接到了这样的一个任务:请你计算出,把这个矩形分割成两个部分的方法总数。

你不是可以任意地分割这个大的矩形, 必须满足:

分割后,每个部分,至少各自均有一个方格是在大矩形的最外边上(即大矩形最外面一环的方格)。
在这里插入图片描述

输入输出格式
输入格式:
输入文件仅包含两个数字,a和b。

输出格式:
输出仅有1行,这一行仅有一个整数,表示分割的方案总数。

输入输出样例
输入样例#1:
3 2
输出样例#1:
15

看到这题,我十分的束手无策,但是当我认真看完题目之后,发现了

(1<=a,b<=6)

这就为暴力提供了很好的机会

我们可以把这个矩阵想象成一个无向图,然后就是求从一个边界点 出发(不走边界点)到另外一个边界点的方案数

但是这样可能行不通,因为你很难判断这个方案是否走过,我一开始想用状态压缩来判断这种方案是否出现过,后来发现没有这个必要

我们只需要从矩阵一条长和一条宽上的每个点出发,求出到另外一个边界点的方案数,记得不要从矩阵的端点出发

#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e1;
int n,m;
int ans=0;
int dx[4]={-1,0,1,0};//上下左右四个方向 
int dy[4]={0,1,0,-1};
bool map[N][N];//map判断这个点有没有走过 
void dfs(int x,int y)
{
    map[x][y]=1;//把这个点设置为走过 
    if(x==1||y==m||x==n||y==1){//如果到了边界点 
        ans++;
        map[x][y]=0;
        return;
    }
    for(int i=0;i<4;++i){//往四个方向搜索 
        int xx=x+dx[i],yy=y+dy[i];
        if(xx<1||yy<1||xx>n||yy>m||map[xx][yy])continue;
        dfs(xx,yy);
    }
    map[x][y]=0;//回溯 
}
int main()  {
    scanf("%d%d",&n,&m);
    n++;m++;//要多加一个点 
    memset(map,0,sizeof(map));//初始化所有的点都是可以走的 
    for(int i=2;i<n;++i){
        map[i][1]=1;//把这个点设置为不能走 
        dfs(i,2);//直接从下一个点开始搜索,保证不会走边界 
        map[i][1]=0;//回溯 
    }
    for(int i=2;i<m;++i){//同上 
        map[1][i]=1;
        dfs(2,i);
        map[1][i]=0;
    }
    printf("%d\n",ans);//输出 
    return 0;
}

好了,文章就到这里了

其实,我一开始想这个代码的时候发现了一个似乎存在的bug

那就是我从//(x,y)表示(行,列)
(1,2)->(2,2)->(2,1)

(2,1)->(2,2)->(1,2)
不是一样的吗,为什么这样可行?
这个问题让你们自己去想!!!









































提示:
只从两条边开始搜索

### 洛谷 P1719 最大加权矩形 Python 解题思路 对于洛谷 P1719 最大加权矩形问题,可以采用动态规划结合前缀和的方式求解。通过构建二维前缀和数组来加速区间查询效率,进而简化计算过程。 #### 动态规划状态定义 设 `dp[i][j]` 表示以第 i 行 j 列结尾的最大子矩阵权重,则有: \[ dp[i][j]=\max \left(a_{i,j}, a_{i,j}+\sum _{k=0}^{i-1}\sum _{l=j-w+1}^{j}a[k][l]\right)[^1] \] 为了提高效率,在实际编程中会先预处理出每一列的高度范围内的累积高度值,再利用这些信息更新 DP 数组中的最优解。 #### 前缀和优化 考虑到直接枚举所有可能的子矩阵时间复杂度过高,因此引入一维前缀和辅助结构降低运算量。具体来说就是维护一个临时变量记录当前正在考察的一行内连续若干列构成区间的累加值,并不断调整起始位置直到找到全局最大值为止。 ```python def max_weight_rectangle(matrix): rows, cols = len(matrix), len(matrix[0]) # 计算每行的前缀和 prefix_sum = [[0] * (cols + 1) for _ in range(rows)] for r in range(rows): for c in range(cols): prefix_sum[r][c + 1] = prefix_sum[r][c] + matrix[r][c] result = float('-inf') # 枚举上下边界 for top in range(rows): temp_row_sums = [0] * cols for bottom in range(top, rows): # 更新当前层的累计高度 for col in range(cols): temp_row_sums[col] += matrix[bottom][col] current_max_subarray = kadane_algorithm(temp_row_sums) result = max(result, current_max_subarray) return result def kadane_algorithm(nums): """Kadane's algorithm to find the maximum subarray sum""" best_sum = current_sum = nums[0] for num in nums[1:]: current_sum = max(num, current_sum + num) best_sum = max(best_sum, current_sum) return best_sum ``` 此算法的时间复杂度主要取决于两重循环遍历所有的上界下界的组合以及调用一次 Kadane 算法 O(n),总体为 \(O(N^3)\),其中 N 是输入矩阵较小维度大小。空间复杂度则由存储前缀和所需额外开销决定,即 \(O(MN)\),M 和 N 分别代表给定网格的高度与宽度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值