[2022编思1062]找出最少动作数
[2022编思1062]找出最少动作数
题面
有一个栈,这个栈有\(m\)个状态,每个状态记为\(S_i\)每个状态里面有\(n\)种数字,数字\(i\)有\(a_i\)个。
考虑从全空,依次经历\(S_1...S_m\),让操作数最小化。
sov
是一个神奇的区间DP。
考虑对于某个区间\(S_i...S_j\),从开始塞进去不用动的数字有\(C_{i,j}\)个,这个区间要进行\(f_{i,j}\)次操作,转移可以是:
\(f_{i,j} = min(f_{i,j}, f_{i,k} + f_{k+1,j} - 2 * C_{i,j})\)
结束
code
#include<stdio.h>
#include<string.h>
#define min(a, b) (a > b ? b : a)
#define MAXN 105
int a[MAXN][MAXN];
int c[MAXN][MAXN];
int f[MAXN][MAXN];
int n, m;
int main()
{
scanf("%d %d", &m, &n);
for(int i = 1; i <= m; ++i)
{
for(int j = 1; j <= n; ++j)
{
scanf("%d", &a[i][j]);
}
}
for(int i = 1; i <= m; ++i)
{
int mi;
for(int k = 1; k <= n; ++k)
{
mi = 0x3f3f3f3f;
for(int j = i; j <= m; ++j)
{
mi = min(a[j][k], mi);
c[i][j] += mi;
}
}
}
memset(f, 0x3f, sizeof(f));
for(int i = 1; i <= m; ++i) f[i][i] = 2 * c[i][i];
for(int len = 1; len <= m; ++len)
{
for(int l = 1; l + len - 1 <= m; ++l)
{
int r = l + len - 1;
for(int k = l; k <= r; ++k)
{
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] - 2 * c[l][r]);
}
}
}
printf("%d", f[1][m]);
}