[关闭]
@sensitive-cs 2017-02-17T08:08:54.000000Z 字数 2080 阅读 777

还未理解动态规划。。。

hdu 1003 :max sum
题意:
给出一个数组,计算这个数组中一段连续的数字的最大的和。
思路:
wa了无数次,是还没有理解动态规划吧。。。看了百度百科对于最大子段和的动态规划解法,才理解了一点。此题所求的是max(a[i] + a[i + 1] + ... + a[j],1 <= i <= j <= n)。由此可得转移方程是dp[j] = max(dp[j-1] + a[j],a[j])(为啥啊)。我的理解是如果说dp[j-1]已经小于0了的话,那么a[i]再加上一个小于0的数肯定会使得后面的和减小,所以就把当前的dp[i]置为a[i]。这道题很恼火的地方是记录最大值的开始位置和结束的位置。我使用的方法并不能准确的记录开始的位置,去看了一下discuss,居然有仁兄和我使用一样的方法,他记录开始位置是首先找出最大值和结束位置,利用这两个值去推出开始位置,真是让我叹服。另外还有一种不需要数组的方法,一并记录一下。
代码:mine

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. using namespace std;
  5. int a[100005];
  6. int dp[100005];
  7. const int minn = -1e9 - 1;
  8. int main()
  9. {
  10. int t;
  11. scanf("%d",&t);
  12. for (int k = 1;k <= t;k++)
  13. {
  14. int n;
  15. scanf("%d",&n);
  16. memset(a,0,sizeof(a));
  17. memset(dp,0,sizeof(dp));
  18. for (int i = 1;i <= n;i++){ dp[i] = minn;scanf("%d",&a[i]);}
  19. int st = 1,en = 1;
  20. int maxx = a[1];
  21. dp[1] = a[1];
  22. for (int i = 2;i <= n;i++)
  23. {
  24. if (dp[i-1] > 0) dp[i] = a[i] + dp[i-1];
  25. else
  26. {
  27. dp[i] = a[i];
  28. }
  29. if (dp[i] > maxx)
  30. {
  31. maxx = dp[i];
  32. en = i;
  33. }
  34. }
  35. int sum = 0;
  36. for (int i = en;i >= 1;i--)
  37. {
  38. sum += a[i];
  39. if (sum == maxx)
  40. {
  41. st = i;
  42. break;
  43. }
  44. }
  45. printf("Case %d:\n%d %d %d\n",k,maxx,st,en);
  46. if (k != t) printf("\n");
  47. }
  48. return 0;
  49. }

借鉴:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int t;
  5. scanf("%d",&t);
  6. for (int k = 1;k <= t;k++)
  7. {
  8. int sum = 0,maxx = -1001;
  9. int tmp = 1,st = 1,en = 1;
  10. int n;
  11. scanf("%d",&n);
  12. for (int i = 1;i <= n;i++)
  13. {
  14. int a;
  15. scanf("%d",&a);
  16. sum += a;
  17. if (sum > maxx)
  18. {
  19. maxx = sum;
  20. st = tmp;
  21. en = i;
  22. }
  23. if (sum < 0)
  24. {
  25. sum = 0;
  26. tmp = i + 1;
  27. }
  28. }
  29. printf("Case %d:\n%d %d %d\n",k,maxx,st,en);
  30. if (k != t) printf("\n");
  31. }
  32. return 0;
  33. }

poj 1050:to the max
ps:n^4的复杂度居然a了,我也不知道说什么好。。。但是一次就a,真是一次就好啊。
题意:
给出一个矩阵,找出其中和最大的子矩阵的和。
思路:
枚举从哪一行开始,然后枚举横向长度为0到n-1,之后再一行一行向下扫描,不断更新最大值,最后输出最大值,其实dp数组也是完全没有必要的。这题是借鉴了最小子段和的思路。把一个方块看成一条线来处理的。
代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int a[105][105];
  4. int dp[105];
  5. int sum(int f,int st,int len)
  6. {
  7. int ans = 0;
  8. for (int i = 0; i < len;i++)
  9. ans += a[f][i+st];
  10. return ans;
  11. }
  12. int main()
  13. {
  14. int n;
  15. int res = -300;
  16. memset(a,0,sizeof(a));
  17. memset(dp,0,sizeof(dp));
  18. scanf("%d",&n);
  19. for (int i = 1;i <= n;i++)
  20. for (int j = 1;j <= n;j++)
  21. scanf("%d",&a[i][j]);
  22. for (int i = 1;i <= n;i++)
  23. {
  24. int maxx = -200;
  25. for (int len = 0;len + i <= n;len++)
  26. {
  27. int tmp = 0;
  28. for (int k = 0; k <= len;k++)
  29. tmp += a[1][i+k];
  30. for (int k = 2;k <= n;k++)
  31. {
  32. int tmp0 = sum(k,i,len);
  33. if (tmp < 0) tmp = tmp0;
  34. else tmp = tmp0 + tmp;
  35. if (tmp > maxx) maxx = tmp;
  36. }
  37. }
  38. dp[i] = maxx;
  39. if (maxx > res) res = maxx;
  40. }
  41. printf("%d\n",res);
  42. return 0;
  43. }

ps:有一种n^3的解法,mark一下,过一段时间用这个思路,写一下,提示:压缩矩阵。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注