Kickstart Round G 2017 Problem C. Matrix Cutting

12 篇文章 0 订阅

Problem C. Matrix Cutting

This contest is open for practice. You can try every problem as many times as you like, though we won't keep track of which problems you solve. Read the Quick-Start Guide to get started.
Small input
17 points
Large input
25 points

Problem

Prof Shekhu has a matrix of N rows and M columns where rows are numbered from 0 to N-1 from top to bottom, and columns are numbered from 0 to M-1 from left to right. Each cell in the matrix contains a positive integer.

He wants to cut this matrix into N * M submatrices (each of size 1 * 1) by making horizontal and vertical cuts. A cut can be made only on the boundary between two rows or two columns.

Prof Shekhu invites his best student Akki for this job and makes an interesting proposition. Every time Akki makes a cut in a submatrix, before he makes the cut, he is awarded a number of coins equal to the minimum value in that submatrix. Note that with every cut, the total number of submatrices increases. Also, cuts in any two different submatrices are independent and likewise, Akki is awarded independently for the cuts in different submatrices.

Now, Akki has various ways in which he can make the cuts. Can you help him by maximizing the total number of coins he can gain?

Input

The first line of the input contains an integer T, the number of test cases. T test cases follow. The first line of each test case contains two integers N and M, as described above.
Next, there are N lines of M positive integers each; these describe the matrix.

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the maximum possible number of coins that Akki can be awarded, if he makes the cuts in optimal order.

Limits

1 ≤ T ≤ 100.
1 ≤ each value in the matrix ≤ 105.

Small dataset

N = 1.
1 ≤ M ≤ 10.

Large dataset

1 ≤ N ≤ 40.
1 ≤ M ≤ 40.

Sample


Input 
 

Output 
 
3
2 2
1 2
3 4
2 3
1 2 1
2 3 2
1 2
1 2

Case #1: 5
Case #2: 7
Case #3: 1

In Sample Case #1, there are two possible ways in which Akki can make the cuts.

  1. Suppose that Akki first cuts the matrix horizontally. He is awarded the minimum value in the matrix: 1. Then he has to make vertical cuts in the two submatrices ([1, 2] and [3, 4]), for which he gets 1 and 3 coins, respectively.
  2. Suppose that Akki first cuts the matrix vertically. He is awarded the minimum value in the matrix: 1. Then he has to make horizontal cuts in the two submatrices (which have the transposes [1, 3] and [2, 4]), for which he gets 1 and 2 coins, respectively.
The first strategy is better, and the answer is 5.

In Sample Case #2, Akki can be awarded at most 7 coins. One of the optimal ways is to first make the only horizontal cut to earn 1 coin. Then, in the upper submatrix [1, 2, 1], Akki can first make the cut immediately to the right of first column and then the cut immediately to the right of second column to earn a total of 2 coins. Similarly, in the lower submatrix [2, 3, 2], Akki can first make the cut immediately to the right of second column and then the cut immediately to the right of first column to earn a total of 4 coins.

In Sample Case #3, there is only one cut to be made.


题意:给一个N*M的矩阵,要切成N*M个小矩阵,每切一个矩阵就把当前矩阵的最小值取出来加到成绩里面去。

问所有切法里面成绩的最大值。(只能沿着边沿横着切或者竖着切)

思路:记忆化搜索,dp[a][b][c][d]表示左上角坐标是(a,b),右下角坐标是(c,d)的矩阵被切成小矩形后,所能得到

的最大值。

#include <bits/stdc++.h>
using namespace std;
const int N = 41;

#define PI acos(-1)
typedef long long ll;
#define INF 0x3f3f3f3f
int mod = 1000000007;
int rec[N][N];
int dp[N][N][N][N];
int dfs(int a, int b, int c, int d)
{
	if (a == c && b == d)
	{
		dp[a][b][c][d] = 0;
		return 0;
	}
	if (~dp[a][b][c][d])
	{
		return dp[a][b][c][d];
	}
	int tmp = rec[a][b], ret = 0;
	for (int i = a; i <= c; i++)
		for (int j = b; j <= d; j++)
			tmp = min(tmp, rec[i][j]);
	for (int i = a; i < c; i++)
	{
		int cur = tmp;
		cur += dfs(a, b, i, d);
		cur += dfs(i+1, b, c, d);
		ret = max(cur, ret);
	}

	for (int i = b; i < d; i++)
	{
		int cur = tmp;
		cur += dfs(a, b, c, i);
		cur += dfs(a, i+1, c, d);
		ret = max(ret, cur);
	}
	return (dp[a][b][c][d] = ret);
}
void run()
{ 
	 int n, m;
	 scanf("%d%d", &n, &m);
	 for (int i = 0; i < n; i++)
	 	for (int j = 0; j < m; j++)
	 		scanf("%d", rec[i] + j);
	 memset(dp, -1, sizeof(dp));
	 printf("%d\n", dfs(0, 0, n-1, m-1));
}

int main()
{
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	int T, cas = 1;
	scanf("%d", &T);
	
	while (T--)
	{ 
		printf("Case #%d: ", cas++);
		run();
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值