poj1722 SUBTRACT
应该是基础的dp练手题
线性dp最主要的就是关于阶段的划分,这个题中我没想到的一点就是开状态的时候使用了前i个数能合成的数来记录
我自己的想法就是类似于区间dp这样的记录方法,这种方法确实开了很多冗余的状态而造成了整道题卡住……
题目中的添减号和括号,实际上可以转化为添加号,这样子最后输出的时候就可以通过把加号换成括号和减号来进行输出。还好spj。
Code:
#include <cstdio> #include <cstring> using namespace std; const int N = 105; const int T = 20005; const int Trans = 10000; int n, t, a[N]; char dp[N][T], op[N]; int main() { scanf("%d%d", &n, &t); t += Trans; for(int i = 1; i <= n; i++) scanf("%d", &a[i]); memset(dp, 0, sizeof(dp)); dp[2][a[1] - a[2] + Trans] = '-'; for(int i = 2; i < n; i++) for(int j = 0; j < (Trans << 1); j++) if(dp[i][j] != 0) { if(j + a[i + 1] <= (Trans << 1)) dp[i + 1][j + a[i + 1]] = '+'; if(j - a[i + 1] >= 0) dp[i + 1][j - a[i + 1]] = '-'; } for(int i = n; i >= 2; i--) { op[i] = dp[i][t]; if(dp[i][t] == '+') t -= a[i]; else t += a[i]; } int cnt = 0; for(int i = 2; i <= n; i++) if(op[i] == '+') { printf("%d\n", i - cnt - 1); cnt++; } for(int i = 1; i <= n; i++) if(op[i] == '-') puts("1"); return 0; }