矩阵取数游戏
矩阵取数游戏
https://ac.nowcoder.com/acm/problem/16645
动态规划
题意:
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 * 2i,其中i表示第i次取数(从1开始编号);
4.游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入描述:
第1行为两个用空格隔开的整数n和m。
第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。
输出描述:
输出一个整数,即输入矩阵取数后的最大得分。
分析:
首先一个重要的发现:
我们发现这一题其实和矩阵没有关系!!!
我们求矩阵最后的答案其实就是求每一行最后的答案再相加
这是个重要的发现,这意味着我们可以不管矩阵一说,直接关注对于一个数组如何去求题目条件中的最大值
看数组:
[a1,a2,a3,a4,a5,a6,a7,a8,a9]
我们想一想我可能取a1,那么接下来我将会在[a2,a3,a4,a5,a6,a7,a8,a9]中寻找答案
如果我取a9,那么接下来我将会在[a1,a2,a3,a4,a5,a6,a7,a8]中寻找答案
其实我们看到题目条件可以取行尾也可以取行末时,就应该意识到这很可能是个区间dp
给出状态
dp[i][j]表示在[i,j)中从2^1开始的最大值
状态转移方程:
dp[i][j] = max(2^1input[i]+2dp[i+1][j],2^1input[j-1]+2dp[i][j-1])
注意到数组遍历比较困难,所以我们选择记忆化搜索.
ll solve(int l,int r) { if (dp[l][r] != -1)return dp[l][r]; if (r - l == 1)return dp[l][r] = (ll)in[l] * 2; return dp[l][r] = max(solve(l + 1, r) + in[l], solve(l, r - 1) + in[r-1]) * 2; }
但是,重要的是数据范围超过了long long了,所以最简单的直接用python吧
代码如下,注意细节
max_n = 100 a = [0 for i in range(max_n)] dp = [[-1 for j in range(max_n)] for i in range(max_n)] n = 0 m = 0 def solve(l,r): if dp[l][r] != -1: return dp[l][r] if r - l == 1: dp[l][r] = a[l] * 2 else: dp[l][r] = max(solve(l + 1, r) + a[l], solve(l, r - 1) + a[r - 1]) * 2 return dp[l][r] n,m = map(int,input().split()) ans = 0 for i in range(1,n+1): s = input().split() for j in range(len(s)): a[j+1] = int(s[j]) dp = [[-1 for j in range(max_n)] for i in range(max_n)] ans+=solve(1,m+1) print(ans)