标签:out 最优 ret 小问题 ble min ... cstring 记忆化
DP
题目链接:https://www.luogu.org/problem/show?pid=1005
题目大意:
有一个n * m的矩阵,玩一个取数游戏,每次从1到n行取行首或行尾乘2的
取的次数次方为这次取数的得分,求得分最大值。
A:每次取每行最大不就行了?定义f[i][j]为取到第i次,到第j行的max。
for(int i = 1;i <= m;++ i){
for(int j = 1;j <= n;++ j){
f[i][j] = maxx(f[i][j - 1] * a[j][s],f[i][j - 1] * a[j][e]);
}
}
B:还有个次数次方呢...
A:那每次取最小
B:你怎么知道后面一定会更优?
A:……那怎么办?
B:为什么不可以用你说的方法呢?
A:因为我这个方法不能保证这个状态下是最优的。
B:因为不论取左边还是取右边都会影响后面的状态。
B:这个问题熟不熟悉?
A:嗯,方格取数!!当时也是分开走会影响后面的状态!!
B:怎么处理的来着?
A:加维度!!
END.
这个题第一眼看上去感觉好简单,
然后发现思路明明是贪心啊QAQQ,
然后感觉好难,
但是不要紧,一点点分析,把大问题转化成小问题,
比如这个题,
要取m次,先看取1次?要取n行,先看取1行?要取1行,先看只有1个,2个,3个数的方法?
1个就不说了QAQQ,
如果有两个数,a b为一行,
如果取走b剩下a,就加上b * ...直接和另一种情况取min
如果有3个数 a b c,
可以取走a or c,剩下b,
即b之前的状态可能是a b 或是 b c,
这两种情况取走a或c都有可能成为答案,那就都记下来,
4个数 a b c d,一样的,
在更新剩下b c的状态的时候,
他之前的状态也有两种:a b c或者 b c d,
两种情况取走a或取走d也都可以成为答案,都记录,
咦?有没有发现a b c的情况我们之前明明已经更新过了?(取3个数的时候)
也就是说,b c在所在的位置,所组成的区间,我们已经更新过了?
可以记忆化,那一定可以dp,
那怎么设计状态呢?
要存一个当前取的次数,当前取到哪一行,还有??
看上面上面上面!!不是已经知道b c更新过了么?
也就是说怎么存b c这段区间呢?
存一段区间可以存起点终点或者起点长度,
随便选一个好了,
设计状态:f[i][j][s][e]:第i次取,到第j行,s到e区间的答案
Codes:
f[i][j][s][e] = maxx(f[i][j][s - 1][e] + a[j][s - 1] * (1 << i),f[i][j][s][e + 1] + a[j][e + 1] * (1 << i));
哇哦4维啊好长,有没有发现我在用 i 更新 i ?在用 j 更新 j ?
扔掉扔掉,i可以边输入边处理(这里就不写了)
这样状态定义可以是这样;
f[i][s][e]:到第i行,s到e区间的答案。
就是这样啦~
f[i][s][e] = maxx(f[i][s - 1][e] + a[i][s - 1] * (1 << t),f[i][s][e + 1] + a[i][e + 1] * (1 << t));
(其中t是第t次取数,可以通过s和e来求)
然后最终答案很明显是每行答案之和啦~(当时我这里写错QAQQ忘了统计。。。)
Codes:
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<algorithm>
5 #define ll long long
6 using namespace std;
7 const int N = 80 + 5;
8 ll a[N][N],f[N][N][N],n,m;
9 ll maxx(ll x,ll y){if(x > y) return x;return y;}
10 int main(){
11 scanf("%d%d",&n,&m);
12 for(int i = 1;i <= n;++ i){
13 for(int j = 1;j <= m;++ j){
14 scanf("%d",&a[i][j]);
15 }
16 }
17 for(int i = 1;i <= n;++ i){
18 for(int s = 1;s <= m;++ s){
19 for(int e = m;e >= s;-- e){
20 int t = m - (e - s) - 1;
21 f[i][s][e] = maxx(f[i][s - 1][e] + a[i][s - 1] * (1 << t),f[i][s][e + 1] + a[i][e + 1] * (1 << t));
22 }
23 }
24 }
25 ll ans = 0;
26 for(int i = 1;i <= n;++ i){
27 ll ans1 = 0;
28 for(int j = 1;j <= m;++ j)
29 ans1 = maxx(ans1,f[i][j][j] + a[i][j] * (1 << m));
30 ans += ans1;
31 }
32 cout << ans << ‘\n‘;
33 return 0;
34 }
未完待续~
标签:out 最优 ret 小问题 ble min ... cstring 记忆化
原文地址:http://www.cnblogs.com/Loizbq/p/7742366.html