题意:一个长为 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;
}