题意:一个长为 N (1 <= N <= 100)的序列(1 <= ai <= 100),一次操作为删除 a[i] 和 a[i + 1],然后将它们的差(a[i] - a[i + 1])放入该位置,问 N - 1 次操作后得到 T (-10000 <= T <= 10000)的操作顺序是什么?
题目链接:http://poj.org/problem?id=1722
——>>每次操作相当于给 a[i] 和 a[i + 1] 加括号做减法,那么把所有的括号去掉后就是对序列第一次做减法,后面或加法或减法。。
状态:dp[i][j] 表示前 i 个数的运算结果为 j 时最后一次的运算符号。。("+" 或 "-")
状态转移方程:
dp[i + 1][j - a[i + 1]] = ‘-‘;
dp[i + 1][j + a[i + 1]] = ‘+‘;
#include <cstdio> #include <cstring> const int MAXN = 100 + 10; const int MAXT = 20000 + 10; const int MID = 10000; int N, T; int a[MAXN]; char dp[MAXN][MAXT]; char op[MAXN]; void Read() { for (int i = 1; i <= N; ++i) { scanf("%d", a + i); } } void Dp() { if (N == 1) return; memset(dp, 0, sizeof(dp)); dp[2][a[1] - a[2] + MID] = '-'; for (int i = 2; i < N; ++i) { for (int j = 0; j < (MID << 1); ++j) { if (dp[i][j] != 0) { dp[i + 1][j - a[i + 1]] = '-'; dp[i + 1][j + a[i + 1]] = '+'; } } } } void GetPath() { int t = T + MID; for (int i = N; i >= 2; --i) { op[i] = dp[i][t]; if (op[i] == '+') { t -= a[i]; } else { t += a[i]; } } } void Output() { int done = 0; for (int i = 2; i <= N; ++i) { if (op[i] == '+') { printf("%d\n", i - 1 - done); ++done; } } for (int i = 2; i <= N; ++i) { if (op[i] == '-') { puts("1"); } } } int main() { while (scanf("%d%d", &N, &T) == 2) { Read(); Dp(); GetPath(); Output(); } return 0; }
时间: 2024-10-14 23:24:50