ACM_JLINE.

矩阵取数游戏

字数统计: 1k阅读时长: 5 min
2019/03/05 Share

矩阵取数游戏

原题链接:传送门

今天的DP总算是算水的了

题目大意

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n × m 的矩阵,矩阵中的每个元素ai,aj 均为非负整数,游戏规则如下:

  1. 每次取数时须从每行各取走一个元素,共nn个。经过mm次后取完矩阵内所有元素;

  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;

  3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 × ( 2 ^ i), 其中i表示第i次取数(从1开始编号);

  4. 游戏结束总得分为m次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

题解

直接DP转移, 虽然数字很大, 知道是高精度,先开个了 int ,过了几个点, 大概知道 DP 应该没有什么问题

然后高精度一加就 A 了。

Code block

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;

int n, m;
int a[85][85];
int f[85][85][85]; //行 左 右

int main(){
scanf("%d%d", &n, &m);

for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%d", &a[i][j]);
}
}

for(int k = 1; k <= n; k++){ //行
for(int l = 1; l <= m; l++){ //长度
for(int x = 1; x <= m; x++){ //左端
if(x + l - 1 > m) continue;
f[k][x][x+l-1] = max(f[k][x][x+l-1], f[k][x+1][x+l-1] + a[k][x] * (int)pow(2, m-l+1));
f[k][x][x+l-1] = max(f[k][x][x+l-1], f[k][x][x+l-2] + a[k][x+l-1] * (int)pow(2, m-l+1));
}
}
}

int ans = 0;
for(int i = 1; i <= n; i++){
ans += f[i][1][m];
//printf("%d\n", f[i][1][m]);
}

printf("%d\n", ans);
return 0;
}

//然后再加个大数

Code block

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;

const int MAXN = 85;
const int Mod = 10000;
int n, m;
int a[85][85];

struct HP {
int p[15], len;
HP() {
memset(p, 0, sizeof p);
len = 0;
}
void print() {
printf("%d", p[len]);
for (int i = len - 1; i > 0; i--) {
if (p[i] == 0) {
printf("0000");
continue;
}
for (int k = 10; k * p[i] < Mod; k *= 10)
printf("0");
printf("%d", p[i]);
}
} //四位压缩的输出
} f[MAXN][MAXN][MAXN], base[MAXN], ans; //行 左 右

HP operator + (const HP &a, const HP &b) {
HP c; c.len = max(a.len, b.len); int x = 0;
for (int i = 1; i <= c.len; i++) {
c.p[i] = a.p[i] + b.p[i] + x;
x = c.p[i] / Mod;
c.p[i] %= Mod;
}
if (x > 0)
c.p[++c.len] = x;
return c;
}

HP operator * (const HP &a, const int &b) {
HP c; c.len = a.len; int x = 0;
for (int i = 1; i <= c.len; i++) {
c.p[i] = a.p[i] * b + x;
x = c.p[i] / Mod;
c.p[i] %= Mod;
}
while (x > 0)
c.p[++c.len] = x % Mod, x /= Mod;
return c;
}
HP max(const HP &a, const HP &b) {
if (a.len > b.len)
return a;
else if (a.len < b.len)
return b;
for (int i = a.len; i > 0; i--)
if (a.p[i] > b.p[i])
return a;
else if (a.p[i] < b.p[i])
return b;
return a;
}

void BaseTwo() {
base[0].p[1] = 1, base[0].len = 1;
for (int i = 1; i <= m + 2; i++){
base[i] = base[i - 1] * 2;
}
} //预处理出2的幂

int main(){
scanf("%d%d", &n, &m);

BaseTwo();

for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%d", &a[i][j]);
}
}

for(int k = 1; k <= n; k++){ //行
for(int l = 1; l <= m; l++){ //长度
for(int x = 1; x <= m; x++){ //左端
if(x + l - 1 > m) continue;
f[k][x][x+l-1] = max(f[k][x][x+l-1], f[k][x+1][x+l-1] + base[m-l+1] * a[k][x] );
f[k][x][x+l-1] = max(f[k][x][x+l-1], f[k][x][x+l-2] + base[m-l+1] * a[k][x+l-1]);
}
}
}


for(int i = 1; i <= n; i++){
ans = ans + f[i][1][m];
//printf("%d\n", f[i][1][m]);
}

ans.print();
return 0;
}

//大数模板 Ctrl c + Ctrl v emmmmm

CATALOG
  1. 1. 矩阵取数游戏
    1. 1.1. 原题链接:传送门
      1. 1.1.1. 题目大意:
      2. 1.1.2. 题解:
      3. 1.1.3. Code block
      4. 1.1.4. Code block