首页 > 代码库 > POJ1722 动态规划
POJ1722 动态规划
POJ1722
问题重述:
给定一个数组a[1,2,..,n] 。定义数组第i位上的减操作:把ai和ai+1换成ai - ai+1。输入一个n位数组以及目标整数t,求一个n-1次操作序列,使得最后剩下的数等于t。
分析:
显然最后剩下的整数是在初始数组中各个元素前添加正负号后相加得到的结果,其中a1的符号必为正,a2必为负。可以通过动态规划确定每个元素的符号。
令dp[i][j]表示从前往后计算到第i个数时结果为j的a[i]前的符号:dp[i][j] = 1表示a[i]取正号;dp[i][j]=-1表示a[i]取负号;dp[i][j] = 0表示当前结果无法取到j。那么假如dp[i-1][j] != 0, 则有dp[i][j + a[i]] = 1, dp[i][j -a[i]] = -1。最后可以通过dp[n][t]倒序计算出每个元素前的符号。
取正号的元素可以看成进行了两次减操作。因此,可以先从左到右对取正号的元素进行一次减操作,再从左到右对每个元素进行减操作即可得到结果。
AC代码
1 //Memory: 8364K Time: 63MS 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 6 using namespace std; 7 8 const int maxn = 105; 9 const int maxt = 20010;10 const int offset = 10005;11 int n, t;12 int a[maxn];13 int dp[maxn][maxt];14 int ans[maxn];15 16 void dynamic()17 {18 memset(dp, 0, sizeof(dp));19 dp[1][a[1] + offset] = 1;20 dp[2][a[1] - a[2] + offset] = -1;21 for (int i = 3; i <= n; i++) {22 for (int j = -10000 + offset; j <= 10000 + offset; j++) {23 if (dp[i - 1][j] != 0) {24 dp[i][j + a[i]] = 1;25 dp[i][j - a[i]] = -1;26 }27 }28 }29 }30 31 void output()32 {33 memset(ans, 0, sizeof(ans));34 int s = t + offset;35 for (int i = n; i >= 1; i--) {36 ans[i] = dp[i][s];37 s -= ans[i] * a[i];38 }39 int cnt = 0;40 for (int i = 2; i <= n; i++) {41 if (ans[i] == 1) {42 printf("%d\n", i - cnt - 1);43 cnt++;44 }45 }46 for (; cnt < n - 1; cnt++)47 printf("1\n");48 }49 50 int main()51 {52 scanf("%d%d", &n, &t);53 for (int i = 1; i <= n; i++) {54 scanf("%d", &a[i]);55 }56 dynamic();57 output();58 return 0;59 }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。